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

TMS320F28335 - формирование .bin файла для записи из внутри

А проблема вот какая, когда ОТП-лайк прога в флэшн - её стандартный адрес BEGIN=0x38fff6, но кактолько она скача саму фирмвалю и написала то в BEGIN переписался тоже алрес старта, и разумеется наша ОТП-лайк прога уде ни когда не стартанет. В общем я не нашел и не придумал как это обойти (единственное было с мыслях парсить весь стрим и найдя этот пдоес тупо его игнорить и перехватывать для записи в другое место)

У меня весь стрим принимается по 2 байта и также и пишется сразу же по 1 слову. (Про эту находку я писал ранее)

 

Что-то я не понял последовательность в Вашем описании. У меня в cmd-файле для таких кусков записано неcколько описаний секций вроде этого:

 

.text        :   LOAD = FLASHH, PAGE = 0
                    RUN = RAML0,    PAGE = 0
                    LOAD_START(WriterCodeLoad),
                    LOAD_SIZE(WriterCodeSize),
                    RUN_START(WriterCodeStart)

 

После старта мой загрузчик переписывает эти куски из FLASH в ОЗУ (memcpy, как в примере с FlashAPI) и передает туда управление. Эти куски, записанные в FLASH, из самого FLASH работать не могут, ибо содержат заведомо не те адреса, где лежат, а заточены под ОЗУ.

 

CCS3 не использую, меня от него коробит, кашмарный софт, не удобный ни разу. Но возможно таки прийдется тоже под него проект сделать.

 

Мне приходится работать именно с CCS3, ибо код основной (рабочей) части весь на ассемблере - реал-тайм приложение, управляющее через PWM силовыми ключами. На С слишком много накладных расходов, не хватает тактов, да и бороться с излишней "оптимизацией" кода не очень приятно.

Поделиться сообщением


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

CCS3 не использую, меня от него коробит, кашмарный софт, не удобный ни разу. Но возможно таки прийдется тоже под него проект сделать.

Третий имеет конечно свои недостатки, но именно в одном он круче и четвёртого, и пятого: он может считать прошивку из разлоченного проца, без отдельных ухищрений вне среды разработки. Проект для этого создавать не надо. Я тоже его для этой цели одно время держал на винчестере. :)

 

Мне приходится работать именно с CCS3, ибо код основной (рабочей) части весь на ассемблере - реал-тайм приложение, управляющее через PWM силовыми ключами. На С слишком много накладных расходов, не хватает тактов, да и бороться с излишней "оптимизацией" кода не очень приятно.

Простите, а как связано написание основных функций на ассемблере и версия CCS?

 

Пишу свои функции на асме в 5.5 совершенно спокойно. Оптимизация вообще работать не мешает, с этим в CGTools С2000 всегда всё в порядке было.

Поделиться сообщением


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

Простите, а как связано написание основных функций на ассемблере и версия CCS?

 

Сейчас уже точно не помню, где именно, но когда попробовал в CCS5 поработать с asm-проектом, показалось очень неудобно. Дело привычки, наверное.

 

Хотя :bb-offtopic:

 

Поделиться сообщением


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

Не совсем понял, что Вы хотели этим сказать. Что адрес старта процессора всё время меняется?

У меня 2 уровня, Первый сам OTP, который грузит в ОЗУ вторую, промежуточную прогу, Второй - грузит фирмварю, вторая кстати и записывает её в флеш через флэшАпи. Так вот там адрес точки входа то может меняться, не исключено, ибо она а ОЗУ а а будущем неизвестно как всё повернется.

 

Так это не так, Вы сами задаёте этот адрес. Если Вы посмотрите мой проект для загрузчика и загружаемой программы (файлы .cmd), то найдёте, что там описывается кусок флэша с названием BEGIN на который ложится секция codestart. В секции codestart располагается асмовская инструкция перехода на _c_int00 (), т.е. на функцию main (см. DSP281x_CodeStartBranch.asm)

code_start:
         .if WD_DISABLE == 1
             LB wd_disable ;Branch to watchdog disable code
         .else
             LB _c_int00   ;Branch to start of boot.asm in RTS library
         .endif

Таким образом, не смотря на то что адрес main (_с_int00) может меняться, адрес перехода на _c_int00 всегда остаётся постоянным, и вы его сами задаёте, можете BEGIN положить по любому адресу, который Вам нравится.

да, я знаю, я так пробовал, распалогал по адресу 0x8000 и от туда успешно грузился способом как вы написали ниже. Но как я уже писал адрес точки схода может поменяться.

 

А как Вы до этого осуществляли переход? Всё просто, одна инструкция:

__inline void GotoLoadedProgram(){ asm(" LB 0x3DA000"); }
     __inline void GotoBootLoader(){ asm(" LB 0x3F7FF6"); }

Тут только константой задается, если передать вместо 0x3F7FF6 например _var_addr где будет храниться значение адреса, то по факту будет переход по адресу той самой переменной var_addr, а это точно не то, что мне нужно

 

Что-то я не понял последовательность в Вашем описании. У меня в cmd-файле для таких кусков записано неcколько описаний секций вроде этого:

.text        :   LOAD = FLASHH, PAGE = 0
                       RUN = RAML0,    PAGE = 0
                       LOAD_START(WriterCodeLoad),
                       LOAD_SIZE(WriterCodeSize),
                       RUN_START(WriterCodeStart)

После старта мой загрузчик переписывает эти куски из FLASH в ОЗУ (memcpy, как в примере с FlashAPI) и передает туда управление. Эти куски, записанные в FLASH, из самого FLASH работать не могут, ибо содержат заведомо не те адреса, где лежат, а заточены под ОЗУ.

Если честно я не понял как оно у вас так работает. То что вы описали это классический подход к приложению в флеше. Ведь по идее точка входа даже в вашем случае будет гдето, но чтоб до неё добраться нужно пройти сквозь _c_int00, на адрес который то и будет указывать значение в 0x38fff6.

 

Так вот о чем я и говорил, что если вместо секции OTP, расположить нашу прогу(А), которая на самом деле OTP, только собранная для старта флеш, то будет её точка старта всё в том же 0x38fff6, и как только она скачает новую прошивку для флеша и перезапишет, то в том же 0x38fff6 уже будет указание не на (А) п на нашу новую прогу. Вот что я имел ввиду. И вот это как побороть я не понял, все пробы что делал не венчались успехом.

Поделиться сообщением


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

У меня 2 уровня, Первый сам OTP, который грузит в ОЗУ вторую, промежуточную прогу, Второй - грузит фирмварю, вторая кстати и записывает её в флеш через флэшАпи. Так вот там адрес точки входа то может меняться, не исключено, ибо она а ОЗУ а а будущем неизвестно как всё повернется.

 

да, я знаю, я так пробовал, распалогал по адресу 0x8000 и от туда успешно грузился способом как вы написали ниже. Но как я уже писал адрес точки схода может поменяться.

Адрес точки входа _с_int00 меняется, но адрес перехода на точку входа _c_int00 не меняется, он через секцию codestart привязан к одному и тому же адресу, т.е. зная этот адрес Вы всегда можете попасть на _c_int00. Для перехода, который выполняет занрузчик при старте программы, удобнее использовать не адрес _c_int00 (адрес самого main), а адрес перехода на _c_int00, т.е. постоянный адрес секции codestart.

Поделиться сообщением


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

Если честно я не понял как оно у вас так работает. То что вы описали это классический подход к приложению в флеше. Ведь по идее точка входа даже в вашем случае будет гдето, но чтоб до неё добраться нужно пройти сквозь _c_int00, на адрес который то и будет указывать значение в 0x38fff6.

 

Так вот о чем я и говорил, что если вместо секции OTP, расположить нашу прогу(А), которая на самом деле OTP, только собранная для старта флеш, то будет её точка старта всё в том же 0x38fff6, и как только она скачает новую прошивку для флеша и перезапишет, то в том же 0x38fff6 уже будет указание не на (А) п на нашу новую прогу. Вот что я имел ввиду. И вот это как побороть я не понял, все пробы что делал не венчались успехом.

 

Так. Давайте еще раз, с самого начала. У Вас в OTP записана программа-загрузчик (отдельный проект, со своим CMD-файлом). Процессор настроен выбором пинов на "boot from OTP", то есть точка BEGIN вашей проги-загрузчика, описанная в CMD-файле, всегда равна 0x380800. Программа записана раз и навсегда (так как OTP). Она откуда-то (неважно) читает какой-то параметр, и делает выбор - загрузить в ОЗУ кусок с FLASH API и передать туда управление для последующей загрузки и записи нового firmware (назовем его "основная программа" для однозначности) в FLASH, либо сразу передать управление в FLASH на уже ранее записанную программу.

 

Адрес точки входа (BEGIN) для FLASH всегда равен 0x33FFF6, он же указывается в CMD-файле при сборке проекта основной программы. А уже по этому адресу лежит переход (LB) на _c_int00 основной программы. То есть ваша программа-загрузчик при отсутствии необходимости обновления основной программы всегда передает управление по одному и тому же адресу 0x33FFF6. Что по этому адресу лежит, зависит от ранее прописанного из бинарника кода. А лежит там обычно "LB _c_int00", естественно, с абсолютным адресом, вычисленным при компиляции кода основной программы. Программе-загрузчику этот адрес знать не нужно - достаточно передать управление на 0x33FFF6.

 

Кусок программы-загрузчика для работы в ОЗУ расположен в проекте в отдельной секции, как и FLASH API, переносится из места хранения (OTP или FLASH, неважно) в ОЗУ через memcpy, адреса хранения в OTP/FLASH (LOAD) и перемещения/выполнения в ОЗУ (RUN) описываются в CMD-файле, как я написал ранее. Их можно задать жестко.

 

Ваша программа-загрузчик, выполняемая в ОЗУ, в случае необходимости обновления читает бинарник основной программы и пишет его содержимое по тем адресам, которые в нем указаны.

 

То есть все адреса известны заранее. Где наши методы (или понимание работы) расходятся?

 

Поделиться сообщением


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

Так. Давайте еще раз, с самого начала. У Вас в OTP записана программа-загрузчик (отдельный проект, со своим CMD-файлом). Процессор настроен выбором пинов на "boot from OTP", то есть точка BEGIN вашей проги-загрузчика, описанная в CMD-файле, всегда равна 0x380800. Программа записана раз и навсегда (так как OTP). Она откуда-то (неважно) читает какой-то параметр, и делает выбор - загрузить в ОЗУ кусок с FLASH API и передать туда управление для последующей загрузки и записи нового firmware (назовем его "основная программа" для однозначности) в FLASH, либо сразу передать управление в FLASH на уже ранее записанную программу.

 

Адрес точки входа (BEGIN) для FLASH всегда равен 0x33FFF6, он же указывается в CMD-файле при сборке проекта основной программы. А уже по этому адресу лежит переход (LB) на _c_int00 основной программы. То есть ваша программа-загрузчик при отсутствии необходимости обновления основной программы всегда передает управление по одному и тому же адресу 0x33FFF6. Что по этому адресу лежит, зависит от ранее прописанного из бинарника кода. А лежит там обычно "LB _c_int00", естественно, с абсолютным адресом, вычисленным при компиляции кода основной программы. Программе-загрузчику этот адрес знать не нужно - достаточно передать управление на 0x33FFF6.

 

Кусок программы-загрузчика для работы в ОЗУ расположен в проекте в отдельной секции, как и FLASH API, переносится из места хранения (OTP или FLASH, неважно) в ОЗУ через memcpy, адреса хранения в OTP/FLASH (LOAD) и перемещения/выполнения в ОЗУ (RUN) описываются в CMD-файле, как я написал ранее. Их можно задать жестко.

 

Ваша программа-загрузчик, выполняемая в ОЗУ, в случае необходимости обновления читает бинарник основной программы и пишет его содержимое по тем адресам, которые в нем указаны.

 

То есть все адреса известны заранее. Где наши методы (или понимание работы) расходятся?

все именно так, только вместо 0x380800, должно быть 0x380400

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

 

Только отличие в том, что мне нужно не только грузиться по тому что в 0x38FFF6, но и возможно по совершенно другому адресу

самый простой пример, на чипе, в разные секции записаны разные версии, и нужно на них уметь перепрыгивать.

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

То есть, цель сделать чуть более разумный и гибкий лоадер. что вобщем-то, мне кажется, удалось.

 

А лежит там обычно "LB _c_int00", естественно, с абсолютным адресом, вычисленным при компиляции кода основной программы. Программе-загрузчику этот адрес знать не нужно - достаточно передать управление на 0x33FFF6.

Вот тут то и проблема, была, которую я уже пофиксил, что в LD передается только константа... щас я могу гибко перепрыгивать в любое место которое узнаю при записи новой версии передав только переменную с значением точки бута.

Ну и второй момент, приложение может быть собрано в бинарик без всякого там _c_int00, а точнее без библиотеки rts2800_ml.lib, конечно это малая вероятность, но тем не менее не исключено тоже

Поделиться сообщением


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

Только отличие в том, что мне нужно не только грузиться по тому что в 0x38FFF6, но и возможно по совершенно другому адресу

самый простой пример, на чипе, в разные секции записаны разные версии, и нужно на них уметь перепрыгивать.

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

То есть, цель сделать чуть более разумный и гибкий лоадер. что вобщем-то, мне кажется, удалось.

Что-то Вам всё рассказывают-рассказывают, а Вы всё равно о своём. Для каждой прошивки свой BEGIN, гле лежит переход на свой _c_int00 и адрес BEGIN == const.

Поделиться сообщением


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

Что-то Вам всё рассказывают-рассказывают, а Вы всё равно о своём. Для каждой прошивки свой BEGIN, гле лежит переход на свой _c_int00 и адрес BEGIN == const.

Так это я уже давно понял, где-то по теме выше, уже это пару раз рассказывали. Я же говорю о другом совсем(ну или немножко)...

в принципе то что я делаю, это не так уж и важно, оно просто не совсем традиционное.

Но если говорить кратко - то тема помогла решить те вопросы что были ранее ))

По этому всем кто помог прояснить и объяснить непонятные моменты - огромное спасибо! :laughing: Я стартанул в разных видах свои прошивки, и получил довольно хороший результат, как мне показалось.

А особенно, !спасибо! doom13 :rolleyes:

Поделиться сообщением


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

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

 

#pragma CODE_SECTION(Cycle, "MY_SEG");

volatile void Cycle(void)

{

тут у меня инициализация PLL,

настройка порта и просто светодиодная мигалка

}

 

Сама по себе функция рабочая, светодиод мигает. Ниже мой cmd файл:

 

 

MEMORY

{

PAGE 0: /* Program Memory */

/* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE1 for data allocation */

 

RAML0 : origin = 0x008000, length = 0x001000 /* on-chip RAM block L0 */

OTP : origin = 0x3D7800, length = 0x000400 /* on-chip OTP */

FLASHH : origin = 0x3D8000, length = 0x004000 /* on-chip FLASH */

FLASHG : origin = 0x3DC000, length = 0x004000 /* on-chip FLASH */

FLASHB : origin = 0x3F0000, length = 0x004000 /* on-chip FLASH */

FLASHF : origin = 0x3E0000, length = 0x004000 /* on-chip FLASH */

FLASHE : origin = 0x3E4000, length = 0x003F80 /* on-chip FLASH */

FLASHD : origin = 0x3E8000, length = 0x004000 /* on-chip FLASH */

FLASHC : origin = 0x3EC000, length = 0x004000 /* on-chip FLASH */

FLASHA : origin = 0x3F4000, length = 0x003F80 /* on-chip FLASH */

CSM_RSVD : origin = 0x3F7F80, length = 0x000076 /* Part of FLASHA. Program with all 0x0000 when CSM is in use. */

BEGIN : origin = 0x3F7FF6, length = 0x000002 /* Part of FLASHA. Used for "boot to Flash" bootloader mode. */

CSM_PWL : origin = 0x3F7FF8, length = 0x000008 /* Part of FLASHA. CSM password locations in FLASHA */

 

ROM : origin = 0x3FF000, length = 0x000FC0 /* Boot ROM */

RESET : origin = 0x3FFFC0, length = 0x000002 /* part of boot ROM */

VECTORS : origin = 0x3FFFC2, length = 0x00003E /* part of boot ROM */

 

 

PAGE 1 : /* Data Memory */

/* Memory (RAM/FLASH/OTP) blocks can be moved to PAGE0 for program allocation */

/* Registers remain on PAGE1 */

 

RAMM0 : origin = 0x000000, length = 0x000400 /* on-chip RAM block M0 */

RAMM1 : origin = 0x000480, length = 0x000380 /* on-chip RAM block M1 */

BOOT_RSVD : origin = 0x000400, length = 0x000080 /* Part of M1, BOOT rom will use this for stack */

RAML1 : origin = 0x009000, length = 0x001000 /* on-chip RAM block L1 */

RAMH0 : origin = 0x3FA000, length = 0x002000 /* on-chip RAM block H0 */

}

 

SECTIONS

{

 

/* Allocate program areas: */

.cinit : > FLASHA PAGE = 0 /*память для глобальных переменных*/

.pinit : > FLASHA, PAGE = 0 /*значения начальной инициализации переменных*/

.text : > FLASHA PAGE = 0 /*содержит исполняемый код и константы*/

codestart : > BEGIN PAGE = 0 /*в codestart сщдержится адрес старта программы BEGIN*/

MY_SEG : > FLASHH PAGE = 0

ramfuncs : LOAD = FLASHB,

RUN = RAML0,

LOAD_START(_RamfuncsLoadStart),

LOAD_END(_RamfuncsLoadEnd),

RUN_START(_RamfuncsRunStart),

PAGE = 0

 

csmpasswds : > CSM_PWL PAGE = 0

csm_rsvd : > CSM_RSVD PAGE = 0

 

/* Allocate uninitalized data sections: */

.stack : > RAMM1 PAGE = 1 /*системный стек (для сохранения контекста процессора при вызове процедур)*/

.esysmem : > RAMM1 PAGE = 1

.ebss : > RAML1 PAGE = 1

MY_SEG : > FLASHH PAGE = 0

/* Initalized sections go in Flash */

/* For SDFlash to program these, they must be allocated to page 0 */

.econst : > FLASHA PAGE = 0 /*инициализация констант (для языка С)*/

.switch : > FLASHA PAGE = 0

 

Flash28_API:

{

-lFlash2809_API_V100.lib(.econst)

-lFlash2809_API_V100.lib(.text)

}

LOAD = FLASHA,

RUN = RAML0,

LOAD_START(_Flash28_API_LoadStart),

LOAD_END(_Flash28_API_LoadEnd),

RUN_START(_Flash28_API_RunStart),

PAGE = 0

 

 

/* Constants caching */

ramconsts : LOAD = FLASHB, PAGE = 0

RUN = RAML1, PAGE = 1

LOAD_START(_RamconstsLoadStart),

LOAD_END(_RamconstsLoadEnd),

RUN_START(_RamconstsRunStart)

 

/* Allocate large memory blocks section: */

data_mem : > RAMH0 PAGE = 1

data_mem2 : > RAMM0 PAGE = 1

 

.reset : > RESET, PAGE = 0, TYPE = DSECT

vectors : > VECTORS PAGE = 0, TYPE = DSECT

}

 

Данная функция записывается в SECTORH. Но вот никак не могу запустить этот код из моей функции main. Пробовал так:

 

int main(void)

{

asm(" LB 0x3D8000");

}

 

и так:

 

int main(void)

{

jumpToAppEntry();

}

 

где jumpToAppEntry(), взятая с форума ti, где обсуждали подобную тему.

 

_jumpToAppEntry:

SETC INTM;

ZAPA;

MOV @SP,#0;

PUSH ACC;

PUSH AL;

MOV AL, #0x0a08;

PUSH AL;

MOVL XAR7, #0x3D8000;

PUSH XAR7;

POP RPC;

POP ST1;

POP ST0;

POP IER;

POP DBGIER;

LRETR;

 

В результате после выполнения asm(" LB 0x3D8000"); или jumpToAppEntry(); всегда в отладчике появляется сообщение : No source available for "0x3d8000"

 

Люди, помогите разобраться. Что я делаю не так?

 

 

Поделиться сообщением


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

Тут было начало разговора, можете глянуть, возможно найдёте что-нибудь полезное.

 

В результате после выполнения asm(" LB 0x3D8000"); или jumpToAppEntry(); всегда в отладчике появляется сообщение : No source available for "0x3d8000"

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

 

Поделиться сообщением


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

 

Ту тему читал в первую очередь. Ничего, что могло бы мне помочь я не нашел. Кстати процессор TMS320F2809. Может будут еще мысли какие нибудь у кого? Буду очень признателен, а то уже отчаялся.

 

 

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

 

Возможно я чего то не до понимаю, но ведь именно по этому адресу расположена моя функция, которую я хочу запустить. Собственно я видел это отладчиком.

 

Поделиться сообщением


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

Не совсем понятно, что Вы хотите сделать. Этим переходом LB 0x3D8000 хотите попасть в функцию Cycle()? А Вы уверены, что 0х3D8000 это её адрес в памяти?

Поделиться сообщением


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

Не совсем понятно, что Вы хотите сделать. Этим переходом LB 0x3D8000 хотите попасть в функцию Cycle()? А Вы уверены, что 0х3D8000 это её адрес в памяти?

 

Лучше опишу конечную цель - это CAN загрузчик. Этим примером я хотел отработать некоторые механизмы этого процесса. Данной темой раньше не занимался и возможно, а скорее точно думаю не совсем в правильном направлении.

 

Сам процесс вижу так: В секторе А, В и т.д. может располагаться основная программа, которая также работает и с CAN. Если приходит команда о перепрошивке, то необходимо запустить загрузчик, который заранее записан в сектор Н и этот загрузчик уже сотрет необходимые страницы памяти и запишет в них основную программу, которую по-блочно будет получать по CAN. С чего начать и на что особенно необходимо обратить внимание? С записью и стиранием флешки я разобрался.

 

А Вы уверены, что 0х3D8000 это её адрес в памяти?

 

В CCS смотрел отладчиком сектор Н и там начиная с адреса 0x3d8000 были данные моей функции Cycle();. Чтобы удостовериться, что это данные именно этой функции, я вызвал эту функцию напрямую из main и убрал строку #pragma. Данные с сектора Н исчезли, зато тот же самый порядок байт оказался в секторе А. Отсюда я сделал вывод, что в первом случае в секторе Н по адресу 0x3d8000 находилась моя функция Cycle();

 

Поделиться сообщением


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

В той теме, если не ошибаюсь, этот процесс расписан. Должно быть две прошивки: одна - загрузчик, вторая приложение. У каждой свой cmd-файл, описывающий память в которой располагается соответствующая программа (загрузчик/приложение). Области памяти загрузчика и приложения не пересекаются.

Возможный вариант работы - при включении питания стартует загрузчик, проверяет записано ли приложение, если записано, то переходит на адрес основной программы. Если подробнее, при включении питания процессор стартует с адреса BEGIN (для f2812 было 0x3F7FF6), там лежит переход на _c_int00, запускается загрузчик. Далее если условия совпали осуществляется переход на BEGIN_APP (адрес старта приложения), тут лежит переход на _c_int00 программы приложения.

 

PS:

В той теме был пример загрузчика и приложения.

Поделиться сообщением


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

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

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

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

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

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

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

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