LINUXTALKS.CO

Блоги - Архив 2024, Июль

Arduino для «старичков». Часть 2. Сборка в консоли.

Блоги — Персональные блоги участников
Группа Персональные блоги участников

Основные моменты из части 1.

– Arduino - это прежде всего, кроссплатформенный фреймворк для программирования микроконтроллеров. Он позволяет писать программы, которые смогут выполняться на основных современных распространенных архитектурах микроконтроллеров, включая AVR, STM32, ESP32, Raspberry Pi Pico.

– Платформа Arduino предоставляет универсальный API, абстрагированный от железа и одинаковый на разных типах микроконтроллеров. Если ваша программа использует только этот API, она будет работать на любом микроконтроллере, для которого есть реализация платформы Arduino. (Это основной плюс, другой такой платформы пока нет).

– Платформа Arduino работает поверх нативной программной платформы, специфичной для каждого микроконтроллера. Поэтому, все возможности нативной платформы (регистры, функции HAL, API ESP-IDF) будут в полной мере доступны прямо в скетче Arduino. Если не хватает возможностей API Arduino, всегда можно использовать любые возможности нативной платформы.

Как мы раскроем основные преимущества платформы Arduino, исходя из сказанного выше? Мы можем писать портируемый между разными архитектурами микроконтроллеров код. Благодаря портируемости Arduino, производители дисплеев, датчиков, всяких дополнительных модулей, микросхем управляемых по I2C и прочего, просто выкладывают драйвер для Arduino, и он может работать на любом микроконтроллере, будь то STM32, AVR, ESP32 и прочие. Write once, deploy everywhere!

Но! Здесь надо сразу понять очень важную вещь. Любое портируемое, абстрагированное, универсальное решение - неизбежно проигрывает в эффективности непортируемому, неуниверсальному, прибитому к особенностям архитектуры, специализированному под конкретный микроконтроллер решению. Поэтому, программы с использованием платформы Arduino будут есть больше ресурсов, будут работать медленнее, использовать железо менее эффективно. Но это не обязательно плохо. На самом деле, нет разницы, вы используете 5% или 55% ресурсов своего микроконтроллера. Пока у вас есть свободные ресурсы. То есть, напрашивается такой традиционный для любого программирования подход:

Трехуровневая система (подход)

  1. Пока проект простой, все делаем через API Arduino, получаем максимально портируемый код.

  2. Проект развивается. Эффективности начинает не хватать - в нужных местах, бутылочных голышках, начинаем использовать API нативной платформы.

  3. Если проект еще дальше развивается и усложняется, приходится выжимать из железа все возможности какие есть - отказ от платформы Arduino, перенос проекта на нативную платформу полностью.

Все эти три этапа мы рассмотрим в этом цикле статей, в последующих частях.

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

ЧТО ТАКОЕ IDE и почему так не любят Arduino IDE

Для новичка IDE это бог и царь. Это такая волшебная программа, которая «делает хорошо». Без IDE вообще нельзя запрограммировать ничего. Или можно? Но как?

На самом деле, любая IDE устроена довольно просто. В основном, это всего лишь текстовый редактор, специализированный для написания кода. Но когда вы написали код - его надо откомпилировать, собрать прошивку. А потом записать прошивку в микроконтроллер. И вот тут сюрприз! Это делает не IDE! Ваша IDE только запускает в фоне утилиты командной строки, которые и компилируют ваш код. Потом вызывает утилиту командной строки, которая записывает код в микроконтроллер.

Получается, что мы можем взять любой текстовый редактор кода (да хоть Блокнот, но лучше специализированный редактор), которых имеется на любой вкус, и написать код скетча. Потом вызвать те самые утилиты командной строки, которые его компилируют и прошивают в микроконтроллер. И получить то же самое. Arduino IDE просто объединяет все это в одной программе, чтобы было удобно.

Но на самом деле Arduino IDE это не лучший представитель мира IDE. Она черезчур тяжеловесна, предоставляя при этом минимум возможностей, и скрывая многую полезную информацию по умолчанию. И основная функция - текстовый редактор - реализована в ней совсем примитивно. Не идет ни в какое сравнение с удобством Vim или Emacs. Отказавшись от Arduino IDE, можно делать все то же самое, на гораздо более слабой машине, заметно быстрее, заметно лучше понимая что происходит, и тратя заметно меньше нервов.

РАБОТА С ARDUINO В КОНСОЛИ

Итак, выбор текстового редактора оставим за читателем. Можно использовать любой, какой больше нравится. Главный вопрос - где взять Arduino для командной строки теперь? Нам нужно установить Arduino-CLI (https://arduino.github.io/arduino-cli/dev/). Набор утилит доступен для всех ОС, для Linux - еще и для ARM. Но, поскольку этот проект является полным СПО, он присутствует просто в репозиториях дистриутивов Linux. То есть - устанавливаем пакет arduino-cli из репозитория.

Теперь создадим минимальный скетч, на котором мы можем проверить, как идет сборка прошивки в arduino-cli. Для простоты, напишем скетч блинкалки светодиодом на нашей плате. Практически на всех отладочных платах есть хотя бы один светодиод, помигаем им. Наберем вот такую программу и сохраним в файл blink.ino. Имя файла должно совпадать с именем папки, в которой сохранен этот файл! Поэтому создадим папку blink и поместим файл blink.ino в нее.

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

Функция setup вызывается один раз, при включении платы. У нас она настраивает ножку LED_BUILTIN, к которой подключен светодиод распаянный на плате, как выходную. Далее в функции loop, которая вызывается раз за разом при работе, ножка включается и выключается функцией digitalWrite.

Обратите внимание, что вся работа в этом скетче делается только через функции Arduino! А это значит, что на любой совместимой плате, с любым микроконтроллером, будет работать вот этот скетч, без каких-либо изменений. Если написать два таких примера без платформы Arduino, для Atmega358 и для STM32F411, то увидите что они отличаются чуть менее чем полностью. Ножки настраиваются по-разному, ножки включаются и выключаются по-разному (похож принцип, но конкретные названия регистров совсем разные). STM32F411 еще потребует инициализации тактового генератора, простыней кода на пол-экрана. А с Arduino у нас получается один и тот же скетч, который работает и там и там. И еще на многих платформах.

Далее, вся работа сводится к вызовам утилиты arduino-cli с нужными ключами. Это позволяет сделать все то же, что делается в Arduino IDE. Рассмотрим простейший пример. Пусть у нас есть скетч, написанный в текстовом редакторе, надо его собрать и прошить в микроконтроллер. Я предпочитаю для этих задач, использовать GNU Make. Можно применить и скрипт на bash, но Make имеет ряд удобств. Правда, сейчас они не сильно проявятся из-за дубовости arduino-cli. Поместим в папку blink файл Makefile Выглядеть наш Makefile будет примерно так:

all:
	arduino-cli -v compile -e --fqbn STMicroelectronics:stm32:Nucleo_64 --board-options "pnum=NUCLEO_F411RE"

upload:
	arduino-cli -v upload -e --fqbn STMicroelectronics:stm32:Nucleo_64 --board-options "pnum=NUCLEO_F411RE"

flash:
	st-flash write build/STMicroelectronics.stm32.Nucleo_64/Nucleo_64.ino.bin 0x8000000

monitor:
	arduino-cli monitor -p /dev/ttyACM0 --config "baudrate=115200"

erase:
	st-flash erase

Теперь разберем его построчно. Если вы не знакомы с синтаксисом Make, прочитайте про него сначала. Кратко - Makefile состоит из целей, для каждой из них прописаны команды, как эту цель собрать. Цели здесь - это all, upload, flash и т. д. После цели ставим двоеточие, на следующей строке с отступом пишем команды, нужные для реализации цели. По умолчанию, если выполнить make в каталоге с нашим Makefile, собирается цель all. Разберем опции ее команды.

-v - это флаг, который включает подробную информацию по ходу сборки.

compile - команда «компилировать».

-e - файлы с бинарной прошивкой, помещать в папку проекта, а не в temp. Нам это надо включать обязательно, чтобы потом работали команды для прошивки в микроконтроллер без зубодродительных путей в temp.

--fqbn - полное название борды (отладочной платы, под которую все это делается). Вот с этим несколько сложнее. В моем примере это плата Nucleo-64. Это имя платы, надо уметь найти для своей платы. Для этого вызываем команду arduino-cli board list при подключенной плате. Но работает это далеко не всегда! Для моей Nucleo-64, просто выводится Unknown вместо имени платы. Поэтому ищем FQBN из списка вручную, список получаем командой arduino-cli board listall. В левой колонке - названия плат, в правой FQBN, просто копируем его как есть и подставляем в опцию --fqbn.

--board-options "pnum=NUCLEO_F411RE" - мало одного FQBN. Борда может иметь несколько вариантов, например моя Nucleo-64 имеет микроконтроллер STM32F411RE, и это не есдинственный и не дефолтный вариант Nucleo-64. Поэтому надо указывать еще и pnum. И надо тоже знать, какие варианты pnum есть для вашей борды. Для этого выполняем команду arduino-cli board details --fqbn STMicroelectronics:stm32:Nucleo_64. И видим для этой борды, с одним и тем же названием Nucleo-64, список из штук 20 разных вариантов pnum (то есть на эти борды может ставится штук 20 разных микроконтроллеров, какой-то из них - ваш. На чипе написано название).

Вот и все! Эта команда соберет скетч. Обратите внимание, что мы не указываем тут файл скетча. И другие файлы, если у вас проект состоит из нескольких модулей. Система сборки Arduino находит их сама, она просто собирает все что лежит в папке проекта. После сборки, в папке build внутри проекта мы получим бинарники прошивки в разных форматах.

Теперь это надо записать в микроконтроллер. Для этого цель upload. Что в ней:

upload - команда «загрузить».

Все остальные опции те же самые, что при сборке. Эта команда находит программатор, или способ прошивки, прописанный в глубине Arduino для вашей платы, и заливает прошивку. Для Nucleo-64 - используется программатор ST-Link, распаянный на самой плате, и работающий в режиме Mass Storage. То есть, ОС видит подключенную плату как флешку, arduino-cli просто кидает файл прошивки на эту «флешку». Это просто, но имеет свои минусы. Поэтому рассмотрим еще второй способ прошивки - через не связанную с arduino, родную утилиту st-flash от STM32. Для этого цель flash. Внутри нее - стандартная команда заливки прошивки через st-flash. Теперь используется тот же программатор STLink, распаянный на плате, но уже в нормальном режиме - непосредственно, STLink`a. В этой команде нам надо указать путь в bin файлу прошивки.

А что, если надо полностью стереть flash память микроконтроллера? Я вообще не нашел как это сделать нормально средствами Arduino. Поэтому используем родной st-flash, цель erase в Makefile.

Ну и конечно же, самая фишка Arduino IDE - отладочный терминал! Как мы его заменим? Очень просто - для этого выполняем make monitor. Цель monitor запускает режим терминала прямо в… терминале Linux! Здесь:

-p - указываем виртуальный COM порт, который создается при подключении платы. Найти его не трудно командой dmesg сразу после втыкания платы. Читаем ее вывод, и там все видно.

--config "baudrate=115200" - настраиваем скорость порта. В вашем скетче задана скорость для Serial интерфейса, задаем здесь точно такую же.

После этого, все что в скетче печатается через Serial, мы начинаем видеть в терминале Linux, из которого вызвана команда.

Если у вас другая отладочная плата, надо заменить в Makefile значения FQBN и pname. Если платформа не STM32, то цели flash и erase надо убрать. Для сборки прошивки, заливки ее на плату, и подключения монитора сообщений выполняем:

$ make
$ make upload
$ make monitor

Вот - базовая работа с Arduino из командной строки. Помимо этого, конечно же, понадобится установить модули среды Arduino для вашей борды, и библиотеки Arduino, если вы их используете. Это может быть сделано либо через Arduino IDE, и все утановленное в ней будет доступно в arduino-cli. Либо через сам arduino-cli, как это сделать я подробно расписывать не буду, все понятно по документации на arduino-cli.

Теперь мы можем писать скетчи на Arduino API, компилировать их и прошивать. То есть уровень 1 по моей трехуровневой системе. В следующей части рассмотрим практический пример такого скетча, с переходом на уровень 2 (нативные возможности).

 ,

JamesHolden ()

Программатор SPI и i2c для линуксятников

Блоги — Персональные блоги участников
Группа Персональные блоги участников

photo-2024-07-22-21-42-39.jpg

Как известно, разработчики большинства популярных программаторов редко озадачиваются поддержкой Linux в своём софте. И из бюджетных устройств мы можем видеть во flashrom разве что доисторические медленные программаторы без автоопределения уровней типа ch341, tl866 первой версии и самосборного Postal3.

Итак, представляем новый бюджетный программатор spi и i2c eeprom Ra©©oon flash explorer. Программатор представляет микросхемы в системе как диск. Работа простая - файл прошивки скопировал/удалил/записал, то есть работает с любой операционной системой, которая умеет монтировать USB флешки. С телефонами на Android в том числе, с айфонами не проверял, сорян

bfae7199-d5fc-4862-9ae2-b3068ff6aad9.jpg

Микросхема представляется хосту в виде обычного двоичного файла, с которым можно работать напрямую без полной перезаписи, а так же копировать и перезаписывать.
GD25LB64: чтение 16сек, запись 1 минута ровно. 1,8v
W25Q64FV: чтение 19сек, запись 1 минута 9сек. 3.3v

Работает со spi и i2c памятью.
Полный автодетект микросхемы и напряжения питания. Отсутствует необходимость в переходнике на 1.8 В.
Детект работы через прищепку, детект ошибок при ините.
Детект помех на шине.
Детект перевернутого подключения и детект перегрузки с отключением питания.
Не требуются драйверы.
Встроенный тестер инициализации.

Сборка и разработка российские. Для пользователей операционных систем на основе ядра Linux, не избалованных обилием SPI программаторов, Ra©©oon flash explorer по сути безальтернативен

Постоянная поддержка от разработчика в телеграмм канале.
Ценник 2000 руб. плюс доставка(пока только почта РФ) 350 руб.
Возможность заказа набора для самостоятельной сборки 1000 руб. плюс доставка.
Добавляйтесь в ТГ канал. Там все ссылки, обсуждение, описание, инструкции для заказа.
https://t.me/raccoon_prog

Также программатор теперь можно заказать Авито доставкой https://www.avito.ru/pogar/tovary_dlya_kompyutera/programmator_raccoon_4081191958?utm_campaign=native&utm_medium=item_page_android&utm_source=soc_sharing

 , ,

Kaschenko ()

Ардуино для «старичков». Часть 1. Философия

Блоги — Персональные блоги участников
Группа Персональные блоги участников

«Старички» - это люди с большим опытом использования юникс-систем и разработки под них. То есть - мы.

МИКРОКОНТРОЛЛЕРЫ

Мы все, так или иначе, сталкивались с разработкой под микроконтроллеры. Какие для этого есть классические инструменты? Например, для платформы Atmel - если мы разрабатываем из-под Linux, то инструменты все те же, которые используются для разработки под сам Linux! У нас есть avr-gcc, есть тот же самый GNU Make, плюс к этому нужна программа, которая будет работать с программатором и записывать прошивку в микроконтроллер. В Linux это консольная утилита, конечно же. Например, avrdude.

При помощи этого набора консольных (!) утилит писались проекты, в любом редакторе, в любом IDE. Это было очень удобно, эффективно и красиво.

Но! Мы немного забыли о том, что все это, и использование Linux в первую очередь, сильно имеет крен в сторону профессиональной разработки. Сложно представить какого-нибудь любителя-дачника, который хочет сделать автоматическую поливалку парника, и ради этого начинает учить bash и GNU Make. Естественно, он использует Windows, и там несколько другие подходы. В Windows весьма неудобно работать с набором консольных утилит, да это и не принято, поэтому там мы ставим один такой монстро-GUI-бандл всего, под названием IDE. Вместо божественного Vim! И этот бандл, он как бы, ест ресурсы! И куда менее удобен чем Vim, в качестве редактора кода. Вот этот момент сразу запомним - в Linux у нас упор на консольные утилиты, в Windows нам нужна цельная GUI среда которая делает все. И эта среда будет жирная.

Но есть в embedded сфере еще более серьезная проблема. Вот допустим, вы написали код поливалки парника для Atmega8. А я решил его использовать тоже, но у меня STM32F407. Куда мне засунуть ваш код? То есть - решения получаются непортируемы между разными микроконтроллерами. Даже в пределах одной платформы! А основной принцип программирования нам что говорит - надо переиспользовать код!

И вот тогда, некоторые умные люди взяли и сделали такую штуку как

ARDUINO

Как понять, что это такое? Тут надо немного пошевелить мозгами. Это не совсем то, чем оно кажется с первого взгляда. Вы считаете, что Arduino - это вот такая отладочная платка, UNO, с микроконтроллером AVR на ней? Да, в том числе и она, но смысл то вообще не в этом! Посмотрите как выглядит Arduino UNO - там есть гребенка с пинами GPIO (дискретные входы-выходы), есть гребенка с аналоговыми ножками (входами АЦП), есть ножки UART, SPI, I2C. И (!!!) их расположение на плате - это стандарт! Это де-факто стандарт всей этой сферы. А дальше, есть море всех вот этих плат расширения к Arduino, которые просто втыкаются в эти СТАНДАРТНЫЕ гребенки!

С программной стороны, что это такое? Платформа Arduino - это набор C++ библиотек, предоставляющий СТАНДАРТНЫЙ АБСТРАГИРОВАННЫЙ ОТ РЕГИСТРОВ API для работы с вот этими вот СТАНДАРТНЫМИ ножками Arduino!

А теперь - фокус-покус! Зачем все это нужно нам? Представьте теперь, что я не хочу микроконтроллер Atmega328, а хочу STM32F411, который на порядок круче. Но - при этом я хочу втыкать в него все эти мириады плат расширения, которые понаделали для Arduino. И я хочу брать драйверы для всех этих плат, которые УЖЕ написали для Arduino. Удобно же? Но как это возможно? Микроконтроллер вообще другой!

И вот тут, еще более умные люди, чем те, кто придумал Arduino изначально (а может и они сами, я не вникал), посмотрели внимательно на платформу Arduino и на ее СТАНДАРТ. Ножки, которые есть на гребенках Arduino UNO, есть на всех микроконтроллерах всех платформ! Они есть везде, если это не восьмипиновое чудо, конечно. Но и для него есть варианты.

API платформы Arduino это что? Смотри выше. СТАНДАРТНЫЙ АБСТРАГИРОВАННЫЙ ОТ РЕГИСТРОВ API. Значит, все это может работать на любой аппаратной платформе! Нужно только перенести библиотеки Arduino, реализующие все это, на любую целевую платформу. А дальше, любая программа на C++, которой достаточно вот этого базового СТАНДАРТА, начинает работать на любом микроконтроллере вообще! У нас наконец-то, один и тот же код начинает переноситься между микроконтроллерами. Наступает светлое коммунистическое будущее.

КАК ТЕПЕРЬ ПОНЯТЬ ARDUINO

То есть, современное Arduino - это программная платформа, которая реализует базовый АБСТРАГИРОВАННЫЙ ОТ РЕГИСТРОВ API для всех основных платформ микроконтроллеров. Сюда входит AVR, STM32, ESP32, Raspberry Pi Pico, еще куча всего, в том числе одноплатники с Linux внутри! Да да, смеющиеся над ардуинкой, попуститесь! Эти скетчи, компилируются и работают как приложение линукса. Если у вас такая платформа.

И где-то на задворках всего этого многообразия, есть та самая Arduino UNO с атмегой. Если вы хотите именно ее, то пожалуйста.

А есть, например, такая плата как Nucleo-64. На ней стоит мощный современный микроконтроллер STM32F411, но гребенки… вот сюрприз! Они такие же точно, как у Arduino UNO! То есть все ардуиновские платы расширения втыкаются в нее как в родную.

А ЕСЛИ МНЕ ЭТОГО МАЛО???

И вот он самый главный вопрос человека, знакомящегося с Arduino после 20-летнего опыта хардкор-разработки на регистрах. А если мне мало этого вашего БАЗОВОГО API? Что если мне на STM32F411 надо настроить 6 каналов АЦП в режиме циклического DMA, с запуском преобразования от таймера TIM2, и с периодической вставкой еще 3 инжектированных каналов в этот регулярный набор? ХДЕ В ВАШЕЙ АБДУРИНО ПЛАТФОРМЕ ФУНКЦИЯ КОТОРАЯ ЭТО ДЕЛАЕТ? А? А? А? Как мне через analogRead ардуиновский сделать ВОТ ЭТО?

А никак. Тут нужно понять ключевую, важнейшую вещь! Платформа Arduino работает ПОВЕРХ нативной платформы! Не ВМЕСТО нее, а именно ПОВЕРХ! То есть, функции Arduino внутри себя дергают функции нативной платформы, или регистры, проще говоря. Для STM32 это HAL, для ESP32 это ESP-IDF, и так далее. Для AVR это просто регистры AVR.

То есть, ВСЕ возможности, все функции, все регистры нативной платформы, доступны вам ВМЕСТЕ с API Arduino! Натив никуда не девается! Вы можете прямо в Arduino IDE, прямо в скетче ардуиновском, обратиться к любому регистру, или к любой функции нижележащей платформы! Вы можете ВООБЩЕ не использовать API Arduino в скетче, только натив! Вот это надо ОЧЕНЬ ЧЕТКО ПОНЯТЬ. Если вам не понятно, как продраться через абстракции Arduino, значит просто в этих абстракциях нужных нюансов нет, потому что они платформо-специфичны, а Arduino - это кроссплатформа между микроконтроллерами! Тогда, вы просто берете и напрямую обращаетесь к возможностям нативной платформы. К любым.

Но - если все так хорошо, почему все так плохо? Почему все так хейтят Arduino? Потому что - Arduino IDE. Это фуфло, очень неудачная IDE. И очень жирная. Она все портит, рушит всю красоту. Что же тогда делать? Вспоминаем теперь, что мы на Linux, и у нас - крен в сторону консольных утилит! То есть, мы должны выбросить неудачную IDE, и работать с консольными утилитами, как мы и привыкли.

И, внимание!!! Не обязательно выбрасывать саму платформу Arduino и фигачить на регистрах через avrdude в эти платы, как обычно все деды предлагают! Выборосить надо только IDE. С остальным уже можно работать и извлекать пользу.

На этом закончим с философией, в Части 2 поговорим о практике эффективного применения этой платформы юникс-ветераном.

 ,

JamesHolden ()

Нетбук 2024

Блоги — Персональные блоги участников
Группа Персональные блоги участников

Когда-то, давным-давно, в далёкой-далёкой галактике, у меня был нетбук Асус, году в 2008, наверное, не помню что с ним случилось, вроде у цыган поменял его на коня или героин

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

А вот как бы мне сдампить биос?

Но пару недель назад я прихожу в офис, и там на приёмке что-то маленькое лежит, ну я это маленькое схватил, покрутил в руках и прям кайфанул. Chuwi minibook x это. К сожалению, в маленьком дохлый комбайн, и владелец не против продать его за копейки, а я не против купить

Итак, китайская поделка была приобретена за свои кровные, а значит будет продолжение истории

Дополнительно я приобрёл мини-пк за 12000 рублей с 16 Гб ОЗУ и 1 Тб ссд в качестве донора процессора - процессор вышел почти бесплатным

Реболлим процессор (в процессе я заебал всех знакомых китайцев, и ещё и незнакомых что бы мне продали трафарет для Adler-lake N, но он благополучно нашёлся в Москве)

IMG-20240704-164050.jpg

Плата очень толстая, я хотел посадить процессор одним низом, но в итоге пришлось включать и верхний ИК-излучатель

В итоге получаем вот такую пусечку

IMG-20240704-204621.jpg

С помощью @bo4ok и пользователей форума 4pda удалось распердолить на нём и венду, и линукс

Железяка максимально кайфовая за свои 350 баксов в магазине (мне она, понятно, досталась намного дешевле) - цельный брусок алюминия, тачпад с поддержкой всех жестов, которые бывают и не бывают, великолепный экран (у которого даже edid нет лол, как его пердолить расписали в теме про девайс), производительности более чем достаточно для линукса, 11 венда ворочается тоже норм, но видно что ей тяжеловато

IMG-20240706-193804.jpg

Анало говнет, макбук эйр и хуавей мейтбук х в сильно другой ценовой и размерной категории, так что если вам нужен ультрамобильный ПК, берите этот, не прогадаете

 , ,

Kaschenko ()