Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

Re: Лучше не использовать типы char в stm32?

Вс окт 24, 2021 16:21:02

Уверены? Что-то многовато как-то...

Спойлер
Код:
uint32_t divu10(uint32_t val) { return val * (((1ULL << 35) + 5) / 10) >> 35; }

volatile uint32_t val = 4294967295;

for (uint32_t i = 100; i > 0; i--)
{
   __BKPT();
   volatile uint32_t res = divu10(val);
   __NOP();
}

0x20002330  bkpt 0x0000
0x20002332  movs r5, #0
0x20002334  ldr r3, [sp, #84]   ; 0x54
0x20002336  movs r4, r3
0x20002338  movs r2, r3
0x2000233a  movs r3, r5
0x2000233c  adds r2, r2, r4
0x2000233e  adcs r3, r5
0x20002340  adds r2, r2, r4
0x20002342  adcs r3, r5
0x20002344  lsrs r1, r2, #28
0x20002346  mov r12, r1
0x20002348  mov r0, r12
0x2000234a  lsls r1, r3, #4
0x2000234c  orrs r1, r0
0x2000234e  str r1, [sp, #52]   ; 0x34
0x20002350  lsls r1, r2, #4
0x20002352  str r1, [sp, #48]   ; 0x30
0x20002354  ldr r0, [sp, #48]   ; 0x30
0x20002356  ldr r1, [sp, #52]   ; 0x34
0x20002358  adds r2, r2, r0
0x2000235a  adcs r3, r1
0x2000235c  lsrs r1, r2, #24
0x2000235e  mov r12, r1
0x20002360  mov r0, r12
0x20002362  lsls r1, r3, #8
0x20002364  orrs r1, r0
0x20002366  str r1, [sp, #60]   ; 0x3c
0x20002368  lsls r1, r2, #8
0x2000236a  str r1, [sp, #56]   ; 0x38
0x2000236c  ldr r0, [sp, #56]   ; 0x38
0x2000236e  ldr r1, [sp, #60]   ; 0x3c
0x20002370  adds r2, r2, r0
0x20002372  adcs r3, r1
0x20002374  lsrs r1, r2, #16
0x20002376  mov r12, r1
0x20002378  mov r0, r12
0x2000237a  lsls r1, r3, #16
0x2000237c  orrs r1, r0
0x2000237e  str r1, [sp, #68]   ; 0x44
0x20002380  lsls r1, r2, #16
0x20002382  str r1, [sp, #64]   ; 0x40
0x20002384  ldr r0, [sp, #64]   ; 0x40
0x20002386  ldr r1, [sp, #68]   ; 0x44
0x20002388  adds r2, r2, r0
0x2000238a  adcs r3, r1
0x2000238c  lsrs r1, r2, #30
0x2000238e  mov r12, r1
0x20002390  lsls r1, r3, #2
0x20002392  str r1, [sp, #76]   ; 0x4c
0x20002394  mov r1, r12
0x20002396  ldr r0, [sp, #76]   ; 0x4c
0x20002398  lsls r3, r2, #2
0x2000239a  orrs r0, r1
0x2000239c  str r0, [sp, #76]   ; 0x4c
0x2000239e  str r3, [sp, #72]   ; 0x48
0x200023a0  ldr r2, [sp, #72]   ; 0x48
0x200023a2  ldr r3, [sp, #76]   ; 0x4c
0x200023a4  adds r2, r2, r4
0x200023a6  adcs r3, r5
0x200023a8  lsrs r3, r3, #3
0x200023aa  str r3, [sp, #92]   ; 0x5c
0x200023ac  nop ; (mov r8, r8)

Re: Лучше не использовать типы char в stm32?

Вс окт 24, 2021 18:50:25

https://github.com/bobbl/libaeabi-cortexm0
Человечеще спецом заморачивался в оптимизации cortexm0, и мне кажется этот код уже включён в GCC. Потому как на выхлопе очень похожее получается.
Так легко можно увидеть вложенные циклы на делении __aeabi_uidiv ( u32=u32/u32).
И отсутствие циклов на умножении __aeabi_lmul (u64=u64*u64).

Re: Лучше не использовать типы char в stm32?

Чт окт 28, 2021 00:02:35

Вот вы тут все про оптимизацию, а я уже второй вечер под пивасик выдумываю, как бы реализовать рамп шаговика! Точней, у меня на одном STM32F072 контроллер трех шаговых двигателей. Они могут быть как с обратной связью (квадратурный оптический или магнитный энкодер), так и без нее. И самое неприятное в том, что каждые несколько миллисекунд нужно будет в состоянии разгона или торможения заново вычислять ARR пинающего драйвер ШД таймера! И там, естественно, есть деление на некоторое число: ARR=FREQ/V, а V вычисляется каждый раз как V+=dV (или V-=dV на стадии торможения). Причем, если есть энкодер, на стадии разгона нужно еще проверять, не застрял ли вал вообще (если застрял - снижаем скорость, если снизили до минимальной и все равно кирдык — сигналим: "ахтунг") и нет ли проскальзываний (если есть, то скорость пока не увеличиваем)... Ну и в каждом прерывании таймера ШД нужно проверять концевики.
Трындец, сколько вычислений.
Хотя, с другой стороны, это будет от силы тактов 200-300. Т.е. меньше десятка микросекунд. И лень говорит: "а может, нафиг оптимизации? И так сойдет!"

Добавлено after 1 hour 15 minutes 24 seconds:
Японский городовой! Проблеме построения рампа столько статей посвящено, что задолбаешься читать!!! И у всех более-менее одно и то же (сам подобный алгоритм и нарисовал себе), разве что некоторые особо упорные (или упоротые?) китайцы такой математики накидали, что никакой Cortex-M0 не осилит!

Re: Лучше не использовать типы char в stm32?

Пт ноя 05, 2021 14:56:44

Как сократить операцию сравнения? cmp
https://godbolt.org/z/eT5j7nP3W

Re: Лучше не использовать типы char в stm32?

Вт ноя 09, 2021 01:20:40

https://godbolt.org/z/sx7ernxjj
Деление uint64_t на 10 за 68 тиков, __aeabi_uldivmod из GCC жуёт цифры аж 269 тиков.
Код:
#define MAGICDIV  3435973837UL
const uint32_t divu64_dat[]={
  0x00000000, 0x19999999, 0x33333333, 0x4CCCCCCC, 0x66666666,
  0x80000000, 0x99999999, 0xB3333333, 0xCCCCCCCC, 0xE6666666,};
 
union divrev {uint64_t w64;uint32_t w32[2];}rev;
 
/// 68 cpu clock (DWT->CYCCNT)
uint64_t divu64_10 (uint64_t value, uint8_t *residue)
{
  uint32_t nex;
  union divrev rev;
  union divrev res;
  rev.w64 = value;
  res.w32[1] = ((uint64_t)rev.w32[1] * MAGICDIV >> 35);
  nex = rev.w32[1] - res.w32[1] * 10;
  rev.w32[1] = nex;
  rev.w64 -=  (uint64_t)divu64_dat[nex] * 10;
  res.w32[0] = divu64_dat[nex];
  if (rev.w32[1] != 0) {
          rev.w64 -= (uint64_t)divu64_dat[1] * 10;
          res.w64 += (uint64_t)divu64_dat[1];
          };
  nex = ((uint64_t)rev.w32[0] * MAGICDIV >> 35);
  res.w64 += (uint64_t)nex;
  *residue = rev.w32[0] - nex * 10;
  return res.w64 ;
};
Последний раз редактировалось AVI-crak Вт ноя 09, 2021 16:27:46, всего редактировалось 1 раз.

Re: Лучше не использовать типы char в stm32?

Вт ноя 09, 2021 10:39:59

А какие проблемы на M7? https://godbolt.org/z/71jsT3xM6
На M0 что получится?

Re: Лучше не использовать типы char в stm32?

Вт ноя 09, 2021 10:43:33

Деление uint64_t на 10 за 68 тиков

Код:
for(uint64_t i = -1; i > 0xFFFF'FFFE'0000'0000; i--)
{
    if (i / 10 != divu64_10(i))
        printf("Error: %llu, %llu, %llu\n", i, i / 10, divu64_10(i));
}

>> Error: 18446744069414584319, 1844674406941458431, 1844674406511961702
>> Error: 18446744069414584318, 1844674406941458431, 1844674406511961702
>> Error: 18446744069414584317, 1844674406941458431, 1844674406511961702
>> Error: 18446744069414584316, 1844674406941458431, 1844674406511961702

Re: Лучше не использовать типы char в stm32?

Вт ноя 09, 2021 10:51:10

Reflector, естественно, там переполнение будет. Чтобы с uint64_t работать, нужно промежуточные результаты в uint128_t хранить. А это уж совсем оверхед для микроконтроллера.
Подозреваю, в оригинале все-таки был пример деления uint32_t, а uint64 случайно скопипастился.
Но я бы и с uint32_t проверил: нет ли переполнения. Помнится, у кого-то в алгоритме был сдвиг вправо на 35 — это стопудово работать не будет!

Re: Лучше не использовать типы char в stm32?

Вт ноя 09, 2021 10:55:27

Помнится, у кого-то в алгоритме был сдвиг вправо на 35 — это стопудово работать не будет!

Я приводил код с делением на 10/100/1000/1М, со сдвигами на 35 и т.д.. Быстро подобрал и проверил, потом оказалось gcc делает точно так же :) Длинное умножение на ассме для M0 тоже естественно проверил, пришлось STM32G0 разогнать до 140MHz и подождать минут 20...

Re: Лучше не использовать типы char в stm32?

Вт ноя 09, 2021 12:13:04

Reflector, а, дошло: при сдвиге на 35 теряются три младших бита, но они нам и так не нужны, т.к. мы же делим не по правилам округления, а отбрасывая всю дробную часть!

Re: Лучше не использовать типы char в stm32?

Вт ноя 09, 2021 12:25:37

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

При делении на 10(или умножении на 0.1) результат поместится в 29 бит, т.к. это будет наблюдаться уже при делении на 8, потому 3 дополнительных бита можно использовать для более точных расчетов. Аналогично при делении на 1000 можно дополнительно задействовать 9 бит(2^9 = 512).

Re: Лучше не использовать типы char в stm32?

Вт ноя 09, 2021 16:30:14

>> Error: 18446744069414584319

Упс, GCC усиленно сокращает (uint64_t) операции до (uint32_t), подправил.

Re: Лучше не использовать типы char в stm32?

Вт ноя 16, 2021 01:03:36

Вот вы тут все про оптимизацию, а я уже второй вечер под пивасик выдумываю, как бы реализовать рамп шаговика!

Позавчера таки пришли разъемы, я их запаял вчера и сегодня пре-пре-альфу сделал. Еще полным-полно косяков, но без энкодера свободно крутит шаговик: ускоряет/замедляет. С энкодером чуть похуже: надо отладить алгоритм определения заклинивания, а то пока чуть пальцем нажал - и оно встало (вместо 24В подключил 12, да и вместо 1.7А на движок выдаю 600мА)!
Вот только с делениями оптимизировать нормально не вышло: каждые 10мс при разгоне/торможении нужно новое значение скорости вычислять. v=v₀ + a(t-t₀)/1000 (т.к. t измеряется в миллисекундах). А потом вычислять новое значение ARR: ARR = (((PCLK/(MOTORTIM_PSC+1)) / curspeed[i]) >> ustepsshift[i]) - 1; и проверять его на вхождение в интервал [99, 65535]. Поначалу я сделал минимальным ARR двойку, но процесс ускорения/торможения на высоких скоростях уж очень слух резал (таки получается, что вначале скорость падает вообще в 2 раза), а здесь квант в 1% — более плавно.

Как разберусь с движками, надо будет все остальное отладить по-человечески (особенно кучу сеттеров/геттеров всяких второстепенных). Да и протокол CAN я еще не проверял.

Re: Лучше не использовать типы char в stm32?

Вт ноя 23, 2021 18:01:52

Мама дорогая! printf на микроконтроллере!..
Вы туда еще malloc запихайте ради полного "Щассья".


А чем вам, собственно, не угодил printf? Стандартная СИшная функция, может быть реализована по разному для разных МК или приложений, но по-моему достаточно удобно использовать. Обеспечивает простую переносимость кода.

Да и malloc иногда полезен. Были у меня задачи, когда без него просто не получалось справиться.

Re: Лучше не использовать типы char в stm32?

Вт ноя 23, 2021 19:50:59

А чем вам, собственно, не угодил printf?

Оверхедом. Жутким оверхедом.
Стандартная СИшная функция

Ничуть она не сишная, она из glibc! Не существует "стандартной сишной функции printf"! Если что, вообще не существует стандартных сишных функций! Зато существует стандартная библиотека glibc, вот из нее-то эти функции и берутся.
Вот только никто не линкует прошивки микроконтроллеров с glibc! Для этого даже флаги специальные выставляются...
Да и malloc иногда полезен

Разве что если на МК есть MMU. Иначе malloc нафиг не нужен. Изврат это - вручную заниматься разделением памяти. Всегда есть шанс, что куча наткнется на стек, и получится незапланированный кирдык. А если резервировать для стека достаточно много, то приличный объем памяти вообще никогда не будет использован!

Re: Лучше не использовать типы char в stm32?

Ср ноя 24, 2021 05:17:42

Изврат это - вручную заниматься разделением памяти. Всегда есть шанс, что куча наткнется на стек, и получится незапланированный кирдык.

Ну, если в режиме обезьяны запускать все жирные задачи одновременно(даже те -которые сейчас нафиг не нужны) - то обязательно кончится память, и верхушка malloc налетит на ось. Вот только вопрос, зачем так делать?

Re: Лучше не использовать типы char в stm32?

Ср ноя 24, 2021 09:39:46

А зачем тогда вообще аллокаторы рукожопить, если и так все хорошо работает?
Что до printf, я против printf из glibc, т.к. он полон оверхеда (например, на кой черт разбирать аргументы uint64_t, float и double на 32-битном МК без FPU?). Для вывода целых чисел можно нарисовать свой printf. Я же ограничиваюсь функциями void bufputchar(char c), добавляющей в буфер отправки 1 символ, void addtobuf(char *s), добавляющей в буфер строку, а также char *printu(uint32_t u), char *printi(int32_t i) и char *printuhex(uint32_t u), которые выдают строку с числом.

Re: Лучше не использовать типы char в stm32?

Ср ноя 24, 2021 09:40:36

Ничуть она не сишная, она из glibc!

Только не из glibc (гнутого), а из libc (любого). Но семейство printf в стандарт Си входит, от этого никуда не деться. Другое дело что ее реализацию можно не подключать и соответственно сэкономить килобайт флеша и сколько-то тактов.
Разве что если на МК есть MMU.

При чем здесь MMU? Я бы еще понял MPU - модуль защиты памяти. Но преобразование адресов как поможет?
Кстати, без MMU может быть даже безопаснее: софт может самостоятельно проверять допустимость полученного адреса даже если выделение прошло успешно.

Re: Лучше не использовать типы char в stm32?

Ср ноя 24, 2021 10:00:34

При чем здесь MMU?

При том, что без него вообще руки надо отрывать за использование аллокаторов!

Re: Лучше не использовать типы char в stm32?

Ср ноя 24, 2021 10:13:13

От вас я ждал хоть какой-то аргументации, а не фанатичных воплей.
Ответить