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

Кто любит RISC в жизни, заходим, не стесняемся.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

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

Сообщение Reflector »

[uquote="jcxz",url="/forum/viewtopic.php?p=4110579#p4110579"]Уверены? Что-то многовато как-то...[/uquote]
Спойлер

Код: Выделить всё

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) 
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

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

Сообщение AVI-crak »

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

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

Сообщение Eddy_Em »

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

Добавлено after 1 hour 15 minutes 24 seconds:
Японский городовой! Проблеме построения рампа столько статей посвящено, что задолбаешься читать!!! И у всех более-менее одно и то же (сам подобный алгоритм и нарисовал себе), разве что некоторые особо упорные (или упоротые?) китайцы такой математики накидали, что никакой Cortex-M0 не осилит!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

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

Сообщение AVI-crak »

Как сократить операцию сравнения? cmp
https://godbolt.org/z/eT5j7nP3W
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

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

Сообщение AVI-crak »

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 раз.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

А какие проблемы на M7? https://godbolt.org/z/71jsT3xM6
На M0 что получится?
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

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

Сообщение Reflector »

[uquote="AVI-crak",url="/forum/viewtopic.php?p=4118682#p4118682"]Деление uint64_t на 10 за 68 тиков[/uquote]

Код: Выделить всё

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
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

Reflector, естественно, там переполнение будет. Чтобы с uint64_t работать, нужно промежуточные результаты в uint128_t хранить. А это уж совсем оверхед для микроконтроллера.
Подозреваю, в оригинале все-таки был пример деления uint32_t, а uint64 случайно скопипастился.
Но я бы и с uint32_t проверил: нет ли переполнения. Помнится, у кого-то в алгоритме был сдвиг вправо на 35 — это стопудово работать не будет!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

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

Сообщение Reflector »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4118771#p4118771"]Помнится, у кого-то в алгоритме был сдвиг вправо на 35 — это стопудово работать не будет![/uquote]
Я приводил код с делением на 10/100/1000/1М, со сдвигами на 35 и т.д.. Быстро подобрал и проверил, потом оказалось gcc делает точно так же :) Длинное умножение на ассме для M0 тоже естественно проверил, пришлось STM32G0 разогнать до 140MHz и подождать минут 20...
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

Reflector, а, дошло: при сдвиге на 35 теряются три младших бита, но они нам и так не нужны, т.к. мы же делим не по правилам округления, а отбрасывая всю дробную часть!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

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

Сообщение Reflector »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4118801#p4118801"]при сдвиге на 35 теряются три младших бита, но они нам и так не нужны, т.к. мы же делим не по правилам округления, а отбрасывая всю дробную часть![/uquote]
При делении на 10(или умножении на 0.1) результат поместится в 29 бит, т.к. это будет наблюдаться уже при делении на 8, потому 3 дополнительных бита можно использовать для более точных расчетов. Аналогично при делении на 1000 можно дополнительно задействовать 9 бит(2^9 = 512).
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

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

Сообщение AVI-crak »

[uquote="Reflector",url="/forum/viewtopic.php?p=4118767#p4118767"]>> Error: 18446744069414584319[/uquote]
Упс, GCC усиленно сокращает (uint64_t) операции до (uint32_t), подправил.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

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

Как разберусь с движками, надо будет все остальное отладить по-человечески (особенно кучу сеттеров/геттеров всяких второстепенных). Да и протокол CAN я еще не проверял.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
ddimochka
Встал на лапы
Сообщения: 82
Зарегистрирован: Чт мар 22, 2012 20:28:49

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

Сообщение ddimochka »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4105533#p4105533"]Мама дорогая! printf на микроконтроллере!..
Вы туда еще malloc запихайте ради полного "Щассья".[/uquote]

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

Да и malloc иногда полезен. Были у меня задачи, когда без него просто не получалось справиться.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

[uquote="ddimochka",url="/forum/viewtopic.php?p=4127898#p4127898"]А чем вам, собственно, не угодил printf?[/uquote]
Оверхедом. Жутким оверхедом.
Стандартная СИшная функция
Ничуть она не сишная, она из glibc! Не существует "стандартной сишной функции printf"! Если что, вообще не существует стандартных сишных функций! Зато существует стандартная библиотека glibc, вот из нее-то эти функции и берутся.
Вот только никто не линкует прошивки микроконтроллеров с glibc! Для этого даже флаги специальные выставляются...
Да и malloc иногда полезен
Разве что если на МК есть MMU. Иначе malloc нафиг не нужен. Изврат это - вручную заниматься разделением памяти. Всегда есть шанс, что куча наткнется на стек, и получится незапланированный кирдык. А если резервировать для стека достаточно много, то приличный объем памяти вообще никогда не будет использован!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

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

Сообщение AVI-crak »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4128010#p4128010"]Изврат это - вручную заниматься разделением памяти. Всегда есть шанс, что куча наткнется на стек, и получится незапланированный кирдык.[/uquote]
Ну, если в режиме обезьяны запускать все жирные задачи одновременно(даже те -которые сейчас нафиг не нужны) - то обязательно кончится память, и верхушка malloc налетит на ось. Вот только вопрос, зачем так делать?
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

А зачем тогда вообще аллокаторы рукожопить, если и так все хорошо работает?
Что до 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), которые выдают строку с числом.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

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

Сообщение COKPOWEHEU »

Ничуть она не сишная, она из glibc!
Только не из glibc (гнутого), а из libc (любого). Но семейство printf в стандарт Си входит, от этого никуда не деться. Другое дело что ее реализацию можно не подключать и соответственно сэкономить килобайт флеша и сколько-то тактов.
Разве что если на МК есть MMU.
При чем здесь MMU? Я бы еще понял MPU - модуль защиты памяти. Но преобразование адресов как поможет?
Кстати, без MMU может быть даже безопаснее: софт может самостоятельно проверять допустимость полученного адреса даже если выделение прошло успешно.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4128306#p4128306"]При чем здесь MMU?[/uquote]
При том, что без него вообще руки надо отрывать за использование аллокаторов!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

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

Сообщение COKPOWEHEU »

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

Вернуться в «ARM»