Так получилось, что мне захотелось переделать свой 3D принтер MZ3D-256 на микрошаг 32. Я слышал, что с таким микрошагом принтер издаёт более мелодичные звуки. Забегая вперёд, скажу, что так оно и есть. Но вот незадача, краем уха, я услышал, что честный микрошаг 32 на классической плате Arduino, которая стоит в большинстве современных принтеров – невозможен.

 Проверка показала, что всё так и есть (http://yes3d.ru/blogs/blog/fizicheskie-ogranicheniya-skorosti-v-proshivke-marin-dlya-3d-printerov).

 Начинаем рыться в поисках нового железа и видим, что на рынке, в принципе, имеются платы для 3D принтеров на базе ARM. Кто-то делает на базе STM32, кто-то на базе Atmel. Есть даже точная копия платы Arduino на базе ARM. Тем не менее, все эти платы базируются на ядре Cortex M3, причём все, как один – без блока вычисления с плавающей точкой. Возьмём достаточно распространённую плату, точнее, её контроллер STM32F103ZET и сравним его параметры с базовым контроллером, стоящим в классической Arduino (у прочих плат всё очень похоже)

 

Параметр

ATMEGA2560

STM32F103ZET

ПЗУ

256К

512К

ОЗУ

64К

Каналов ШИМ

12

12 (4 таймера по 3 канала)

Каналов АЦП

16 (1), 10 бит

21 (3), 12 бит

USB

Внешний

Есть

CLKmax

16 МГц

72 МГц

Разрядность данных

8

32 

 

 Казалось бы, вполне неплохой прирост. Но есть тут одна заковыка. Пусть обработка 32 битных целочисленных значений действительно станет проще – всего одна команда ассемблера вместо кучи. Но это всё классно, если

  • Писать с нуля
  • Писать для целочисленных данных

 А что мы имеем в жизни, на что не обращают внимание схемотехники? Ну, во-первых, для оптимизации 8-битного кода почти все переменные в нём именно 8-битные. И как поведёт себя, скажем, 8-битный счётчик, попав в 32-битную среду? Ооооо! Это будет что-то с чем-то! Напишем простенький тест и соберём его с максимальной оптимизацией. Даже не напишем, а возьмём в реальной прошивке Marlin, чтобы не быть обвинёнными в придумывании проблем. 

 

    for(unsigned char e = 0; e < EXTRUDERS; e++) {

       if(current_raw[e] >= maxttemp[e]) {

          target_raw[e] = 0;

          max_temp_error(e);

          #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE

          {

            Stop();;

          }

          #endif

       }

 

 Проследим за переменной e. Как она увеличивается? А вот так!

 

0004b2  1c49              ADDS     r1,r1,#1

0004b4  b2c9              UXTB     r1,r1                 ;451

 

 Вторая команда ассемблера приводит 32 битное значение к 8-битному. Это ещё хороший процессор (даже в пределах THUMB-2 существуют разные наборы команд, кто-то что-то не поддерживает), а у некоторых будет вообще два сдвига влево-вправо. Эти команды совершенно не нужны, но они есть, причём занимают и память, и время на выполнение.

 Вот и получается, что в одном месте выигрываем, в другом – проигрываем. Так что прелести 32-битности хоть и есть, но не такие, какие хотелось бы видеть. И только четырёх с половиной кратный выигрыш в тактовой частоте греет нам душу. Только не говорите мне, что кто-то найдёт время переписать весь код по правилам 32-битной работы. Это долго и муторно, а также требует тестирования, чтобы убедиться в отсутствии сторонних эффектов. Никто этим заниматься просто не станет!

 Но это ещё цветочки. Я не зря многократно написал про целочисленные вычисления. Вот типовой кусок кода Marlin. 

 

  float g=autotemp_min+high*autotemp_factor;

  float t=g;

 Или, скажем:

unsigned long minsegmenttime;

float max_feedrate[4]; // set the max speeds

float axis_steps_per_unit[4];

unsigned long max_acceleration_units_per_sq_second[4]; // Use M201 to override by software

float minimumfeedrate;

float acceleration;         // Normal acceleration mm/s^2  THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX

float retract_acceleration; //  mm/s^2   filament pull-pack and push-forward  while standing still in the other axis M204 TXXXX

float max_xy_jerk; //speed than can be stopped at once, if i understand correctly.

float max_z_jerk;

float max_e_jerk;

float mintravelfeedrate;

unsigned long axis_steps_per_sqr_second[NUM_AXIS];

// The current position of the tool in absolute steps

long position[4];   //rescaled from extern when axis_steps_per_unit are changed by gcode

static float previous_speed[4]; // Speed of previous path line segment

static float previous_nominal_speed; // Nominal speed of previous path line segment

 В общем, прошивка просто изобилует переменными с плавающей точкой и соответствующими вычислениями. Но ни контроллеры Atmel, ни контроллеры Stm32, которые мне доводилось видеть на платах, эти вычисления не поддерживают! Они точно так же, как и на старой доброй AtMega будут эмулироваться программно! Пошустрей, но программно… И это при том, что в принципе, имеются контроллеры Cortex M3, которые такие вычисления поддерживают на аппаратном уровне. Почему разработчики их не заложили? Я просто уверен, что они понятия не имели о внутренностях программы. Потому что схемотехники этих плат совершенно не интересуются программированием.

 Так получилось, что на работе я участвую в разработке RTOS, поэтому просто обязан интересоваться и программированием, и схемотехникой. И посему мой взгяд упал на контролер STM32F4 (с ядром Cortex M4). Давайте расширим уже приведённую таблицу, добавив туда характеристики этого контроллера.

 

Параметр

ATMEGA2560

STM32F103ZET

STM32F4

ПЗУ

256К

512К

1-2M

ОЗУ

64К

192K

Каналов ШИМ

12

12 (4 таймера по 3 канала)

Много (17 таймеров по 2-4 канала)

Каналов АЦП

16 (1), 10 бит

21 (3), 12 бит

32(2), 12 бит

USB

Внешний

Есть

Есть

CLKmax

16 МГц

72 МГц

168 МГц

Разрядность данных

8

32

32

Плавающая арифметика

Нет

Нет

Есть 

 

 Собственно, вот. Сравните прирост на том, что ставят все, и на том, что можно поставить (то есть, сравнивайте сначала столбцы 1 и 2, затем – 1 и 3). Хоть память, хоть быстродействие… Просто когда я вижу очередную плату для 3D принтера на контроллере ARM, я в первую очередь лезу смотреть характеристики. И всегда вижу, что переход на ARM – чисто формальный. Какой смысл улучшать плату, просто поменяв одну архитектуру на другую? Менять, так кардиально. Но увы. В погоне за дешевизной (от которой нас предостерегал герой сказки Пушкина) все почему-то ставят самый-самый-самый дешёвый кристалл, лишь бы ножек было побольше. А уж что чуть более дорогой экземпляр существенно лучше – никого из схемотехников не волнует.

 Давайте сравним цены:

Контроллер

Цена Ali Exprress

Цена TaoBao (покупать в Китае)

STM32F103ZET

330  руб

170 руб

STM32F07ZGTT

560  руб

325 руб

STM32F429ZIT

670 руб

440 руб

 

 На фоне общей цены принтера, разница в 300 рублей не так существенна. В самом же Китае разница совсем несерьёзна (сравниваем первую и вторую строки, о третьей речь пойдёт во второй части, если она выйдет). Платы, наверняка, будут делаться в Китае, так что смотрим на китайские цены. Ну и в чём смысл экономии на спичках?

Заключение

 Этим криком души автор пытался показать разработчикам схем, что не надо гнаться только за словом ARM и числом ножек. Надо ещё заглянуть внутрь, чтобы понять, а действительно ли выбранный контроллер подойдёт для переноса на него имеющейся «прошивки». Автор пошёл именно этим путём, в его 3д принтере MZ3D-256 стоит макетная плата именно с контроллером STM32F4, а в настоящее время идёт разработка собственной платы, собирающей в себе эту макетку и Ramps, но подробности этого дела – тема для отдельной статьи.

 Автор выражает огромную благодарность компании «Инк Маркет», приславшей для опытов запасной принтер, благодаря которому у автора даже когда один принтер полностью разбомблен, всегда имеется возможность что-то допечатать на втором, ну, и просто убедиться в повторяемости резултьтатов.

С уважением В.Ш.