STM32 новичку в ARM что к чему
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: STM32 новичку в ARM что к чему
На АРМ можно себе позволить и float... А в моем плейере концептуально 256 эквивалентно 360 градусам, и далее соответственно пересчет. Погрешность есть, но для автомата светоэффектов она роли не играет.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32 новичку в ARM что к чему
Где вы там флоат увидели? 
Re: STM32 новичку в ARM что к чему
Даже на МК не аппаратно поддерживающих float?Reflector писал(а):Будет быстрее
Проверил, компиль "сильно умный".
Код: Выделить всё
; h = h * (uint32_t) (65536 * (360.0f / 256) + 0.5f) >> 16;
20000314 ldr r3, [r7, #4]
20000316 mov.w r2, #92160 ; 0x16800
2000031A mul.w r3, r2, r3
2000031E lsrs r3, r3, #16
20000320 str r3, [r7, #4]- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32 новичку в ARM что к чему
Да причём тут компилятор? Вы код то читать умеете? Где вы там float в рантайме увидели???
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: STM32 новичку в ARM что к чему
А кто, если не компилятор, делает эти вычисления и подставляет в бинарник сразу готовое число 92160?
Re: STM32 новичку в ARM что к чему
На самом деле можно даже так:
Код: Выделить всё
h = uint32_t(h * Fixed<16>(360.0f / 256));
// str r3, [sp, #0]
// movs r3, #180
// lsls r3, r3, #9
// muls r3, r7
// asrs r3, r3, #16
// str r3, [sp, #12]
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32 новичку в ARM что к чему
Reflector, прекрати насиловать неокрепшие мозги. Всё гораздо проще
Код: Выделить всё
h = h*92160 >> 16; - VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32 новичку в ARM что к чему
А кто, если не компилятор, делает эти вычисления и подставляет в бинарник сразу готовое число 92160?
Это сделал программист, записавший целочисленную константу в таком виде. У компилятора не было никакого выбора, даже у самого тупого.И что-то мне подсказывает, что это
Код: Выделить всё
h = (uint32_t)h*360 >> 8; - Eddy_Em
- Собутыльник Кота
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Контактная информация:
Re: STM32 новичку в ARM что к чему
Float константы удобно цепными дробями задавать. На F072 я так и делаю обычно (особенно если нужно построить таблицу для кусочно-линейной аппроксимации показаний термисторов). Завожу вместо одного массива флоатов два массива uint_16t: числитель и знаменатель. Их по заданной точности считаю в октаве (функция rat).
Вот, например: отградуировал NTC в нужном мне диапазоне (8…90℃), потом несложной функцией в октаве аппроксимировал эту кривую полиномом (с погрешностью не хуже 0.05℃), далее автоматом разбил этот диапазон на N узлов (в данном случае получилось 14) так, чтобы кусочно-линейная аппроксимация между узлами давала точность не хуже 0.1℃ (фактически же можно было меньше узлов делать: сами понимаете, что NTC лучше ±2℃ дать не способны, обычно их заявленная точность вообще 1%, т.е. ±3℃ в диапазоне комнатных температур). На каждом интервале температура вычисляется так: T=T₀+k(ADU-ADU₀), T₀ и ADU₀ затабулированы, а вот для k я посчитал числители и знаменатели при помощи rat(k*10). По умолчанию точность 1e-6, но в данном случае можно было бы даже немного уменьшить числа, установив точность 1e-4 (я этого не делал, т.к. все равно все отлично влезло в int16_t).
И все: если нужно посчитать температуру, дихотомией ищем соответствующий интервал и на нем элементарно считаем температуру. Никаких флоатов не нужно. А вот от деления, к сожалению, избавиться невозможно: точность намного хуже будет, если подбирать числитель под знаменатель, равный определенной степени двойки (да и в этом случае вполне возможна ситуация, когда число перед сдвигом вылезет за пределы int32_t).
P.S. Когда калибровал NTC, оказалось, что в моем диапазоне погрешность была всего-то ±0.5%! Кстати, это совпадает с разбросом показаний домашних китайских "термометров", основанных на тех же 10-килоомных термисторах. Они тоже где-то на полтора градуса врут. Зато для терморегулирования этого с лихвой хватает: что я в +45℃ вентилятор включу, что в +47℃ — охлаждаемой цепи от этого хуже не будет.
Вот, например: отградуировал NTC в нужном мне диапазоне (8…90℃), потом несложной функцией в октаве аппроксимировал эту кривую полиномом (с погрешностью не хуже 0.05℃), далее автоматом разбил этот диапазон на N узлов (в данном случае получилось 14) так, чтобы кусочно-линейная аппроксимация между узлами давала точность не хуже 0.1℃ (фактически же можно было меньше узлов делать: сами понимаете, что NTC лучше ±2℃ дать не способны, обычно их заявленная точность вообще 1%, т.е. ±3℃ в диапазоне комнатных температур). На каждом интервале температура вычисляется так: T=T₀+k(ADU-ADU₀), T₀ и ADU₀ затабулированы, а вот для k я посчитал числители и знаменатели при помощи rat(k*10). По умолчанию точность 1e-6, но в данном случае можно было бы даже немного уменьшить числа, установив точность 1e-4 (я этого не делал, т.к. все равно все отлично влезло в int16_t).
И все: если нужно посчитать температуру, дихотомией ищем соответствующий интервал и на нем элементарно считаем температуру. Никаких флоатов не нужно. А вот от деления, к сожалению, избавиться невозможно: точность намного хуже будет, если подбирать числитель под знаменатель, равный определенной степени двойки (да и в этом случае вполне возможна ситуация, когда число перед сдвигом вылезет за пределы int32_t).
P.S. Когда калибровал NTC, оказалось, что в моем диапазоне погрешность была всего-то ±0.5%! Кстати, это совпадает с разбросом показаний домашних китайских "термометров", основанных на тех же 10-килоомных термисторах. Они тоже где-то на полтора градуса врут. Зато для терморегулирования этого с лихвой хватает: что я в +45℃ вентилятор включу, что в +47℃ — охлаждаемой цепи от этого хуже не будет.
Re: STM32 новичку в ARM что к чему
И что-то мне подсказывает, что это
Код: Выделить всё
h = (uint32_t)h*360 >> 8; Да, результат одинаковый поскольку младший байт нулевой, но и инструкций получится столько-же, просто 360 компилятор получает сдвигая 180 на 1, а для 92160 он сдвигает 180 на 9
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32 новичку в ARM что к чему
Cortex-M4
Cortex-M0+
Код: Выделить всё
h = (uint32_t)h*360/256;
MOV R0,#+360
LDRB R2,[R1, #+2]
SMULBB R2,R0,R2
LSRS R2,R2,#+8
STRB R2,[R1, #+2]Cortex-M0+
Код: Выделить всё
h = (uint32_t)h*360/256;
LDRB R1,[R0, #+2]
MOVS R2,#+180
LSLS R2,R2,#+1
MULS R1,R2,R1
LSRS R1,R1,#+8
STRB R1,[R0, #+2]Re: STM32 новичку в ARM что к чему
а вот для k я посчитал числители и знаменатели при помощи rat(k*10).
Eddy, ну какие числители и знаменатели в 21 веке... Беру у тебя в коде коэффициент 0.028261, умноженный на 10 он получается делением 13 / 46 = 0.282609, что очень близко, но будет тяжелое для M0 деление и коэффициенты приходится рассчитывать самому. В то же время даже мои классы все делают быстрее и автоматически:
Код: Выделить всё
Fixed<12> k(0.028261f);
rtt.printf<"{}, {}, {}\n">(k.rawValue(), (k*10).toStr(), (float)k); // 29634, 0.2826, 2.82611847e-2Тут я задал 12 бит для целой части, соответственно 20 осталось для дробной, а могло быть 18 или 25...
29634 - это (1 << 20) * 0.028261 + 0.5, если умножить это число на 10000 и сдвинуть на 20 бит вправо, то получим 282.
- Eddy_Em
- Собутыльник Кота
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Контактная информация:
Re: STM32 новичку в ARM что к чему
Reflector, хватит уже со своими крестами! Я в эту [censored] лезть не собираюсь!
А вообще, когда я впервые увидел, как абдуринщики флоатами пользуются на 8-битной фигнюшке, так охренел, что даже не знаю… Меня теперь, наверное, даже даблы на cortex-M0 не удивят ☺
Жаль, что там аппаратного деления нет.
А вообще, когда я впервые увидел, как абдуринщики флоатами пользуются на 8-битной фигнюшке, так охренел, что даже не знаю… Меня теперь, наверное, даже даблы на cortex-M0 не удивят ☺
Жаль, что там аппаратного деления нет.
Последний раз редактировалось Eddy_Em Вт ноя 10, 2020 12:10:39, всего редактировалось 1 раз.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32 новичку в ARM что к чему
Reflector выдаёт знания в чистом виде! Вам бы на ус мотать, а вы плюётесь.
- Eddy_Em
- Собутыльник Кота
- Сообщения: 2516
- Зарегистрирован: Пт июл 12, 2019 22:52:01
- Контактная информация:
Re: STM32 новичку в ARM что к чему
VladislavS, у него не знания, а "магия".
Я не собираюсь использовать то, чего не в силах понять.
И про кресты я уже сказал: это — не язык программирования, а какой-то садомазо…
Я не собираюсь использовать то, чего не в силах понять.
И про кресты я уже сказал: это — не язык программирования, а какой-то садомазо…
Re: STM32 новичку в ARM что к чему
хватит уже со своими крестами! Я в эту [censored] лезть не собираюсь!
При чем тут кресты... Смотри, запускаю на STM32G0, там нет умножения 32*32->64, потому оно эмулируется:
Код: Выделить всё
volatile uint32_t val = 10000;
const uint32_t k = (1 << 20) * 0.028261 + 0.5;
uint32_t out = (uint64_t)k * val >> 20; // -> 282Если числа относительно небольшие, то во многих случаях можно обойтись без приведения к uint64_t. А у тебя будет так:
Код: Выделить всё
volatile uint32_t val = 10000;
const uint32_t N = 13;
const uint32_t D = 46 * 10;
uint32_t out = val * N / D; // -> 282
Первый код выполняется примерно за 70 тактов, второй - за 100.
Re: STM32 новичку в ARM что к чему
При том, ушли от понятной формулыReflector писал(а):При чем тут кресты...
Код: Выделить всё
uint8_t value = ((24 * h / 17) / 60) % 6;Давайте поменяем и посчитаем:
Код: Выделить всё
uint8_t value = ((25* h / 18) / 59) % 7;Re: STM32 новичку в ARM что к чему
При том, ушли от понятной формулы
Код: Выделить всё
uint8_t value = ((24 * h / 17) / 60) % 6;Изначально смысл в том, что h нужно умножить на понятные 360/256, а непонятные 24/17 появились в следствии оптимизации для 8-ми биток. Но на ARM это не оптимизация, а ее противоположность, я же напротив код именно ускорил, при этом он также стал менее читаем, точно как и оригинал, что совсем не удивительно. Если просто заменить 24 и 17 на 360 и 256, то будет и понятнее, и быстрее, т.к. вместо деления будет сдвиг.
- Ярослав555
- Поставщик валерьянки для Кота
- Сообщения: 2081
- Зарегистрирован: Пт май 31, 2013 17:14:38
- Откуда: Украина, Винница
Re: STM32 новичку в ARM что к чему
такой вопрос - где-то можно посмотреть как зависит время записи на флеш от питания МК? так получилось что имею почти идентичные платы. и оказалось что на одной из них стирание страницы 128kB уперлось в ватчдог (видимо на грани работало). Увеличив период ватчдога я убрал глюк, но интересно было узнать почему так. МК идентичные, единственная разница что вижу - отстающий имеет на 30мВ ниже питание.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: STM32 новичку в ARM что к чему
К вопросу о том зачем нужны современные компиляторы, языки программирования и их стандарты. Есть у меня в библиотеке функция, которая считает количество установленных в числе бит.Попробовал как она работает на С (убрав синтаксис С++, естественно).
А вот так она у меня в библиотеке на С++ работает. Вычисляется на этапе компиляции, если аргумент позволяет. А он, как и в прошлом примере на С, позволяет.
Господа из комитета по стандартизации посмотрели на всё это безобразие и сказали: "Классный у тебя алгоритм, давай его в стандарт С++20 введём. А ты ещё что-нибудь полезное программируй".
Код: Выделить всё
constexpr auto countSetBits(uint32_t value)
{
auto bits = 0;
while (value)
{
value &= value - 1;
bits++;
}
return bits;
}