Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Кто любит RISC в жизни, заходим, не стесняемся.
Dimon456
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение Dimon456 »

Сравнивай
СпойлерИзображение Изображение
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение VladislavS »

Я же всё показал. Сравнивай сам.
iddqd
Нашел транзистор. Понюхал.
Сообщения: 156
Зарегистрирован: Вс сен 06, 2020 16:06:10

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение iddqd »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3951622#p3951622"]Поигрался я с идеей iddqd, есть 2 варианта:
1 вариант, когда пины располагаются на одном порту, не важно в какой последовательности.
ОЗУ на один пин 4 байта, на 8 пинов 32 байта.[/uquote] Технически на 1 пин - 1 бит на порцию, если -> ODR или 2 бита, если -> BSRR. В допущении port-wide доступа. Port-wide доступ имеет смысл например если там LCD с 8-bit bus развесили или например большая группа светодиодов, etc. В принципе с BSRR это битовая маска + latch, так что можно и меньше пинов за раз ворочать, с ухучшением КПД этой операции.

Если хранить картинку 256*256 точек, да в добавок в цветном изображении, параллельный порт 8 пинов, 256*256*3*32 = 6.291.456 байт.?
Любую идею можно довести до маразма. Слать можно отдельные регионы картинки/небольшие иконки/инициализацию дисплея/etc и размер может быть вменяемым. Кстати и ряд других коммуникаций недурно смотрится в виде make packet -> queue send, а пока оно там send можно чем-то еще заняться. И если там всякое сжатие, ну тогда после decompress и "prepare buffer" из вон того куска наверное ок? А какие еще варианты? Если контроллер шины есть то все просто, но он только в очень разлапистых камнях, они дорогие и роутить печатку заманаешься, в общем это сразу повышает планку. А без него вообще какие варианты? Софтом ногодрыгать? Так это вообще блокирующая операция, на ее время проц недееспособен толком (минус IRQ). А, ну еще RTOS можно, но я не знаю как там с таймингами шины будет, в такие дебри я лезть не собираюсь. Мне от MK нужен нижний уровень и предсказуемость, а не высокие абстракции.

Ну как так можно без кода обойтись? Ведь еще сжать картинку можно, без кода ни как.
Есть варианты когда можно совсем без кода. Типа quasi-hardware PWM, когда целый порт ворочается закольцованым DMA без вмешательства софта вообще. Это будет работать даже если процессорное ядро встрянет. Правда оно тогда не сможет параметры подкручивать, но если это не требовалось, то там целиком железки без участия процессора смогут все сделать.

Значит дма будем запускать только на один пин, а в прерывании выключать канал,
1 пин не эффективно по КПД операции. Оно может ВЕСЬ ПОРТ за транзакцию кантовать. Но да, это потребует определенных компромиссов. Оптимальнее всего выделить весь порт под такое развлечение. А почему бы хардвару не сделать хардвару и софту удобно и быстро?. И да, data -> ODR будет с КПД вплоть до 100%. В BSRR только до 50%, битов в 2 раза больше. Зато есть latch, можно только некоторые биты ворочать. Это даже может сосуществовать с некоторой периферией - AFIO в общем случае не очень интересует что там GPIO пытался вообще изобразить. А какое дело какому-нибудь uart input'у до его бита в ODR?

А теперь вопрос в практическом применении, для чего и за чем? И где тут выигрыш в скорости?
Вы кажется не поняли. Суть идеи: в RAM или Flash заводится буфер. Он описывает sequencing группы пинов. Типа эволюции состояния порта во времени. И конечно же трансферов при этом должно быть уж точно не 1. Иначе нахрена б такое счастье с сетапом DMA. И да, поскольку DMA отпускает шину чтобы процу что-то дать, он рекорд скорости может и не поставит. Но есть одна killer feature. Мы можем "зарядить отправку пакета" или даже "закольцевать отправку буфера" - и заняться своими делами! DMA асинхронен относительно кода проца. Так что основной профит - в асинхронщине этого относительно процессора и подпертости железом. А отсутствие трафика кода по шинам для этой активности - приятный побочный эффект, DMA не процессор, ему для ворочания порции данных не надо инструкции по шине гонять. Если хочется именно 1 бит, именно DMA, ну, не знаю, SPI какой поюзайте, чтоли. Он видите ли десереализует то что в него вгрузили, так КПД операции сильно интереснее, а послать опять же можно "целый пакет" и даже, вероятно, закольцевать, если это за каким-то чертом надо.

[uquote="AVI-crak",url="/forum/viewtopic.php?p=3951673#p3951673"]Для того чтобы графику в жк индикатор писать - нужно дма вместе с таймером использовать.[/uquote] И вас с новым годом. Я попробовал и с mem2mem. Вообще на светодиодах которым я сделал так подобие PWM это прокатило. Но выпадут ли из порта трансферы и прокатят ли уж какие получатся тайминги (дисплею это важно) если расписать "bus seqencing" и весь его пульнуть как mem2mem - вопрос открытый. Желающие могут позырить если у них скоростной многоканальный логический анализатор есть.

[uquote="BlackKilkennyCat",url="/forum/viewtopic.php?p=3951682#p3951682"]PWM в микроконтроллере это значительно больше, чем "ногодрыганье" с определенной частотой, и как только начнётся попытка реализовать его полноценную работу, и глянется на блок-схему, то на DMA останется минимум функционала.[/uquote] Так реализуется только очень базовый вариант PWM, с рядом ограничений. Скажите, а вам никогда не хотелось PWM'нуть сразу МНОГО светодиодов, например? Можно и не PWM'нуть, а "sequence". При том вот так - число выходов "PWM" таки до 16 на порт - и таки в отличие от совсем софтварных эрзацев хорошо подперто железом, вплоть до того что будет долбить указанным (при формировании буфера) duty/последовательностью даже при кончине (или занятости) процессорного ядра. Да еще шину потоком команд не грузит, в отличие от софтэрзацев. А рассуждения о хардварных PWM - это прекрасно, но вот захочется пару десятков каналов "хоть какого-то PWM", для например группы светодиодов - и тогда чего? Хардварных каналов ограниченное количество, и вот для них можно и интереснее и требовательнее применения найти.

PWM до кучи придумался. Несколько интереснее ... скажем так, "штукам с разверткой". Когда куча светодиодов на энном порту имеет некий смысл. Вот там таймер ... может очень круто вписаться. Такой себе аппаратный blitter/display controller, если можно так сказать про такую штуку.
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

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

[uquote="iddqd",url="/forum/viewtopic.php?p=3955397#p3955397"]Но выпадут ли из порта трансферы и прокатят ли уж какие получатся тайминги (дисплею это важно)[/uquote]
Один канал таймера использовать как имитацию ноги WR, вторым каналом пинать дма. И да, дма уже загрузило данные для дальнейшей работы, если хочется - можно грузить целую пачку данных. Потери данных могут возникнуть только в одном случае: другой дма с более высоким приоритетом фигачет в режиме нонстоп.
bob1
Мучитель микросхем
Сообщения: 453
Зарегистрирован: Ср июн 08, 2011 20:25:20
Контактная информация:

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение bob1 »

Продолжение от сюда https://radiokot.ru/forum/viewtopic.php ... start=8840
По поводу тактов возник вопрос.
Команда LDR R0,[R1, #+0]; лежит уже в конвейере. До нее и после команд чтения и записи нет. За сколько тактов должна обработаться? За 2 или 3? процессор STM32G431.

[uquote="jcxz",url="/forum/viewtopic.php?p=4745295#p4745295"]Почему 2/3?[/uquote] Вопрос и возник, что меньше 3 не могу получить, а в теории должно быть 2.
[uquote="jcxz",url="/forum/viewtopic.php?p=4745295#p4745295"]Раз не с кем спариваться, то в вашем случае на CM4 должно быть 2 такта.[/uquote]
Ниже тестовая прога для теста. Лежит в ССM, хотя из флешь также работает. Частота 16МГц.
Изменяя n вычисляем разницу счета таймера 4. Получаем такты за цикл. В меньшем случае 21=7+2+3*4. 7 это 1 тактовые команды, 2 такта переход, 4- количество LDR. 3 выходит такты выполнения команды LDR.
Спойлер

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

/*
#define  reg   (uint32_t) TIM4->CNT
#define  reg1  (uint32_t) TIM4->CNT
#define  reg2  (uint32_t) TIM4->CNT
#define  reg3  (uint32_t) TIM4->CNT
*/

#define  reg   (uint32_t) GPIOA->IDR
#define  reg1  (uint32_t) GPIOA->IDR
#define  reg2  (uint32_t) GPIOA->IDR
#define  reg3  (uint32_t) GPIOA->IDR

/*
#define  reg    bx[0]
#define  reg1   bx[1]
#define  reg2   bx[2]
#define  reg3   bx[3]
*/
__root uint32_t bx[]={1,2,3,4};
__root uint32_t res;

void test (void)@".ccmram"{
   LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);
   LL_DBGMCU_APB1_GRP1_FreezePeriph(LL_DBGMCU_APB1_GRP1_TIM4_STOP); 
  
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
  TIM_InitStruct.Autoreload        = 0xFFFFFFFFU;
  LL_TIM_Init(TIM4, &TIM_InitStruct);

  uint32_t n=6;
   uint32_t  w,w1;
  TIM4->CR1=1; 
//--------------------------  
   do{
     w=reg;
     w1=w1+w;
     w= reg1;
     w1=w1+w;
     w= reg2;
     w1=w1+w; 
     w= reg3;
     w1=w1+w; 
    }
    while (n--!=0) ;
//--------------------------
  res=w1; 
  TIM4->CR1=0; 
 
};
Ниже листинг цикла. Для правильного получения нужно поиграться оптимизацией для разных reg.
Спойлер

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

// 1102 //--------------------------  
// 1103    do{
// 1104      w=reg;
??test_1:
        LDR      R0,[R3, #+0]
// 1105      w1=w1+w;
        ADDS     R2,R0,R2
// 1106      w= reg1;
        LDR      R0,[R3, #+0]
// 1107      w1=w1+w;
        ADDS     R2,R0,R2
// 1108      w= reg2;
        LDR      R0,[R3, #+0]
// 1109      w1=w1+w; 
        ADDS     R2,R0,R2
// 1110      w= reg3;
        LDR      R0,[R3, #+0]
// 1111      w1=w1+w; 
        ADDS     R2,R0,R2
// 1112     }
// 1113     while (n--!=0) ;
        MOV      R0,R1
        SUBS     R1,R0,#+1
        CMP      R0,#+0
        BNE.N    ??test_1
// 1114 //-------------------------- 
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение jcxz »

[uquote="bob1",url="/forum/viewtopic.php?p=4745460#p4745460"]Команда LDR R0,[R1, #+0]; лежит уже в конвейере.[/uquote]Почему такой вывод?
Какова ширина шины CPU, читающей поток команд из данной памяти? Есть ли другие bus-masters, работающие в это время?

[uquote="bob1",url="/forum/viewtopic.php?p=4745460#p4745460"]Ниже тестовая прога для теста. Лежит в ССM, хотя из флешь также работает. Частота 16МГц.
Изменяя n вычисляем разницу счета таймера 4. Получаем такты за цикл. В меньшем случае 21=7+2+3*4. 7 это 1 тактовые команды, 2 такта переход, 4- количество LDR. 3 выходит такты выполнения команды LDR.[/uquote]
А куда указывает R3? Откуда идёт чтение?
И как именно производите замер времени выполнения цикла?

Имхо: тестовый код - некорректный. Длительность выполнения LDR следует измерять не так.
Также необходимо прояснить целевой адрес R3. Вангую, что R3 указывает в тот же регион памяти, где находится код. Отсюда и лишний такт.
bob1
Мучитель микросхем
Сообщения: 453
Зарегистрирован: Ср июн 08, 2011 20:25:20
Контактная информация:

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение bob1 »

[uquote="jcxz",url="/forum/viewtopic.php?p=4745491#p4745491"]Почему такой вывод?[/uquote] Это не вывод, а убрать вопросы про время загрузки команды в конвейер. Про кеш, ускоритель...
[uquote="jcxz",url="/forum/viewtopic.php?p=4745491#p4745491"]Какова ширина шины CPU, читающей поток команд из данной памяти?[/uquote] 64.
[uquote="jcxz",url="/forum/viewtopic.php?p=4745491#p4745491"]Есть ли другие bus-masters, работающие в это время?[/uquote] Нет. Тестовая функция практически в начале main.

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

int main(void){
  SCB->VTOR = CCMSRAM_BASE;
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
  LL_RCC_ForceBackupDomainReset();
  LL_RCC_ReleaseBackupDomainReset(); 
  LL_PWR_EnableBkUpAccess();
  LL_PWR_DisableDeadBatteryPD();
  test();
[uquote="jcxz",url="/forum/viewtopic.php?p=4745491#p4745491"]А куда указывает R3? Откуда идёт чтение?[/uquote] В тестовой функции экспериментировал чтение с TIM4->CNT , GPIOA->IDR и SRAM. Наверху кода выбирается в #define reg*.
[uquote="jcxz",url="/forum/viewtopic.php?p=4745491#p4745491"]И как именно производите замер времени выполнения цикла?[/uquote] Изменяя n. К примеру выбираю n=6. Таймер 4 считает время выполнения кода. Увеличиваю n=7. Опять таймер считает. Разница счетов и дает время выполнения цикла. Увеличивая n на 1, то счет Tаймера 4 растет на одну и туже величину.
[uquote="jcxz",url="/forum/viewtopic.php?p=4745491#p4745491"]Длительность выполнения LDR следует измерять не так.[/uquote] Готов посмотреть и ваш код.
[uquote="jcxz",url="/forum/viewtopic.php?p=4745491#p4745491"]Вангую, что R3 указывает в тот же регион памяти, где находится код.[/uquote] В примере код в ССМ. Код был и во флеши (при enable ICEN bit ). Результат одинаковый. Чтение кода и памяти (куда указывает R3) идет по разным шинам.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение jcxz »

[uquote="bob1",url="/forum/viewtopic.php?p=4745502#p4745502"][uquote="jcxz",url="/forum/viewtopic.php?p=4745491#p4745491"]Какова ширина шины CPU, читающей поток команд из данной памяти?[/uquote] 64.[/uquote]В моём текущем XMC4500 - столько же. Точнее - это ширина шины, читающей из кеша в буфер предвыборки. Ширина шин к памяти - разная, в зависимости от типа памяти. Up to 256 бит.

[uquote="bob1",url="/forum/viewtopic.php?p=4745502#p4745502"]Изменяя n. К примеру выбираю n=6. Таймер 4 считает время выполнения кода. Увеличиваю n=7. Опять таймер считает. Разница счетов и дает время выполнения цикла. Увеличивая n на 1, то счет Tаймера 4 растет на одну и туже величину.[/uquote]Некорректный метод. Не учитывает возможного времени перезагрузки буфера предвыборки при переходе. Также не учитывается невыровненность целевого адреса перехода. И не вижу запрета прерываний на время теста.

[uquote="bob1",url="/forum/viewtopic.php?p=4745502#p4745502"]Готов посмотреть и ваш код.[/uquote]Код (IAR):

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

               SECTION  .text:CODE:NOROOT(2)
               PUBLIC   TestLdr
               THUMB
;extern "C" void TestLdr(u32 const *);
TestLdr:       MRS      R12, PRIMASK
               CPSID    I
               MOVS     R2, #5
               alignrom 2, 0xBF00
TestLdr_01:    MOVS     R3, #1
               LDR      R1, [R0]
               MOVS     R3, #1
               SUBS     R2, R2, #1
               BNE      TestLdr_01
               MSR      PRIMASK, R12
               BX       LR
Вызов из си++:

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

extern "C" void TestLdr(u32 const *);
TestLdr((u32 const *)0x20000000);
Таймеры для измерения тоже не нужны - IAR (у вас же вроде IAR?) сам умеет измерять по отладочному таймеру DWT.CYCCNT. Ставим бряки как на картинке ниже:
Изображение
потом делаем один шаг "step into" чтобы соскочить с бряка (так как на некоторых МК в некоторых памятях это добавляет лишние такты (при soft-бряках)):
Изображение
потом жмём "go". Останавливается на 2-м бряке, смотрим поле "CCSTEP":
Изображение
Делаем рестарт МК, после "step into" вводим в R2 вручную 4, "go", результат:
Изображение
Как видно - у меня разница составила 34-27=7 тактов. Следовательно - длительность LDR = 2 такта. Как и ожидалось.
И нет влияния времени перезагрузки буфера предвыборки при переходе по BNE.

Можно ещё улучшить тест. Исключив возможное влияние перезагрузки буфера предвыборки. После первой пары LDR/MOVS добавляем 2-ю такую же пару:
Изображение
Делаем тест (с тем же числом проходов). У меня получилось == 49 тактов:
Изображение
Считаем (49-34)/5 = 3 такта добавилось. Тоже - как и ожидалось.

В моих тестах 0x20000000 - адрес начала одного из регионов ОЗУ. Код выполняется из другого региона ОЗУ (0x10000000).

Добавлено after 7 minutes 19 seconds:
PS: [uquote="bob1",url="/forum/viewtopic.php?p=4745460#p4745460"]

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

// 1113     while (n--!=0) ;
        MOV      R0,R1
        SUBS     R1,R0,#+1
        CMP      R0,#+0
        BNE.N    ??test_1
[/uquote]Если цель - писать оптимально, то это плохая организация цикла. Используя постфиксную операцию декремента, вы не даёте компилятору использовать флаги результата команды SUBS, заставляя его добавлять ненужную CMP.
Лучше использовать префиксный декремент:

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

int n = N; do { ... } while (--n);
или

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

int n = N - 1; do { ... } while (--n >= 0);
в этих случаях будет одна команда SUBS за которой сразу BNE.
Хотя для целей измерения времени выполнения команды тут конечно всё равно.
bob1
Мучитель микросхем
Сообщения: 453
Зарегистрирован: Ср июн 08, 2011 20:25:20
Контактная информация:

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение bob1 »

Разобрался частично. Вывод: кеш инструкций включен, инструкции должны загружаться по I-bus, данные по D-bus. Загрузка по S-bus добавляет 1 такт в лучшем случае и получается, что с периферии данные считываются за 3 такта.
з.ы. Вопросы по расположению кода (цикла) еще остались. Потом еще поэкспериментирую.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение jcxz »

[uquote="bob1",url="/forum/viewtopic.php?p=4745753#p4745753"]с периферии данные считываются за 3 такта.[/uquote]Ранее вы писали, что читаете из памяти:[uquote="bob1",url="/forum/viewtopic.php?p=4745502#p4745502"]Чтение кода и памяти (куда указывает R3)[/uquote]Почему сразу и спрашивал вас "откуда читаете?" При чтении из периферии есть много влияющих на чтение факторов: какая именно периферия? на какой шине (AHB, APB1, APB2 - для STM32)? какова частота шины?
Даже у разной периферии, находящейся на одной шине, длительность чтения может быть разной. К скорости выполнения LDR это не имеет отношения. Периферия может долго не ставить ready-сигнал, замораживая CPU.

PS: Иногда (на некоторых МК) помогает работа через bit-band область (если она есть в МК). На моих STM32 (STM32F4xx, STM32F1xx) работа с GPIO-потами через bit-band - заметно быстрее, чем через их регистры. Если подходит - можно попробовать переписать работу на bit-band и проверить.
bob1
Мучитель микросхем
Сообщения: 453
Зарегистрирован: Ср июн 08, 2011 20:25:20
Контактная информация:

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение bob1 »

[uquote="jcxz",url="/forum/viewtopic.php?p=4745834#p4745834"]Почему сразу и спрашивал вас "откуда читаете?"[/uquote] Меня интересовала не конкретная задача, а общий случай. Пробовал и код в ссм и читал ram с адреса 0x20000000. Это было в декабре. Код тогда сделал "3 тактах". Просто пришлось больше стыковать друг другу команд чтения и записи. Тогда и возник вопрос про чтение по 2-м тактам. Сейчас созрел задать его :))
[uquote="jcxz",url="/forum/viewtopic.php?p=4745834#p4745834"]какая именно периферия?[/uquote] ADC-результат. AHB2, делителя нет. Частота 32МГц такая же как у ядра SYSCLK. ADC тактируется без деления.
[uquote="jcxz",url="/forum/viewtopic.php?p=4745834#p4745834"]bit-band[/uquote] Возьму на заметку. Нужно было чтение всего слова.
[uquote="jcxz",url="/forum/viewtopic.php?p=4745834#p4745834"]можно попробовать переписать работу на и проверить.[/uquote] Сейчас завал.
[uquote="jcxz",url="/forum/viewtopic.php?p=4745834#p4745834"]К скорости выполнения LDR это не имеет отношения[/uquote] Если так, то еще попробую поиграться, но позже.....
з.ы. Спасибо за идеи. Результат "2 такта" получил.
shalfey
Встал на лапы
Сообщения: 123
Зарегистрирован: Ср май 16, 2012 20:44:38
Откуда: Харків-Україна.

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение shalfey »

не заморачивайся си проще ассемблера, ти будешь оцифровивать ззвук или что на си прекрасно все работает, даже уже плюси суют ни єто уже сноби, в контроллер плюси совать, микропайтон пихают в esp32, ну а тут давай и с++ всунем ми мол крутие, джаву еше всуньте.
shalfey
Встал на лапы
Сообщения: 123
Зарегистрирован: Ср май 16, 2012 20:44:38
Откуда: Харків-Україна.

Re: Ассемблер для STM32. Сложно ли, стоит ли пытаться?

Сообщение shalfey »

[uquote="Shuspano",url="/forum/viewtopic.php?p=3741147#p3741147"]
NStorm писал(а):Пытаться разбираться не стоит. Писать на асме бесперспективно
А что тогда делать? "С" - он же намного сложнее асма, я его просто не осилю.[/uquote] Для STM Си не очень страшний,освой указатели массивы, циклы и тебе хватить такого наваять, если канечно ты не будешь туда операционку пихать.
Ответить

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