STM32 новичку в ARM что к чему

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 386
Зарегистрирован: Чт окт 31, 2013 10:54:32

Сообщение alex38779 »

Спасибо всем за пинки:) Настало время изучить новую периферию в виде DMA :idea:
Контактная информация:
Реклама
Опытный кот
Аватара пользователя
Сообщения: 791
Зарегистрирован: Вт июн 17, 2014 00:34:26

Сообщение baghear »

Добрый день, хочется усыпить МК, и пробудить его по внешнему прерыванию. На выводе A1 этот код работает, на A0 не усыпает.

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

EXTI->IMR |= EXTI_IMR_MR0;
__DSB();
__wfi();
Реклама
Мучитель микросхем
Сообщения: 446
Зарегистрирован: Вс ноя 01, 2015 09:15:16
Откуда: 69.Ржев

Сообщение a797945 »

а двойным:
__wfi();
__wfi();

скажу честно, совет не научный, просто самому однажды пришлось продублировать инструкцию, но объяснить не могу (f103c8). а без нее - врал.
"
EXTI->PR = flag; // RESET event
EXTI->EMR = flag; // SET bit MASK
__WFE(); // SLEEP
__WFE(); // дубль
if ((GPIOA->IDR&ARC_P)) x |=1; // bit7
x=x<<1;
EXTI->PR = flag;
__WFE();
if ((GPIOA->IDR&ARC_P)) x |=1; // bit6
x=x<<1;
EXTI->PR = flag;
__WFE();
...
"
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Утренний кофе навеял пример как С++ "не нужен" для управления умными диодами. Напомню как на STM32 обычно генерируют сигнал управления с помощью DMA и таймера в режиме PWM. Цвет каждого диода представляют в RGB (24 бита - по байту на цвет). Затем из него формируют массив на 24 байт для каждого диода, в котором в каждом байте записано значение длительности "0" или "1", которое DMA автоматически передаёт в таймер для формирования битовой последовательности. При формировании этого буфера ещё и Гамма-коррекцию делают. Один из легко находимых в интернете и уже набивший оскомину пример на Си делает это вот так.
Спойлер

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

uint8_t LEDGamma(uint8_t v)
{
  return (v * v + v) >> 8;
}

struct RGB_t
{
  uint8_t r, g, b;
};

struct PWM_t
{
  uint8_t g[8], r[8], b[8];
}; 

 
static void RGB2PWM(RGB_t *rgb, PWM_t *pwm)
{  
  uint8_t r = LEDGamma(rgb->r);
  uint8_t g = LEDGamma(rgb->g);
  uint8_t b = LEDGamma(rgb->b);
  
  uint8_t mask = 128;
  
  for (int i = 0; i < 8; i++)
  {
    pwm->r[i] = r & mask ? TIM_HI : TIM_LO;
    pwm->g[i] = g & mask ? TIM_HI : TIM_LO;
    pwm->b[i] = b & mask ? TIM_HI : TIM_LO;

    mask >>= 1;
  }
} 

PWM_t pwm_buf[16];
RGB_t rgb_leds[16];
Замерим скорость преобразования на STM32G071 с тактовой 64 МГц.

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

TEST_PIN::set();
for(uint32_t i=0; i<8; i++) 
  RGB2PWM(&rgb_leds[i],&pwm_buf[i]);
TEST_PIN::clear();
Для одного диода 3 мкс, а восьми диодов 25 мкс или 10% процессорного времени. На 48 МГц F0 будет ещё больше.

Ну что же, будем ускорять. Вспоминаем совет Reflector о табличном преобразовании. Сформируем в памяти таблицу, где каждому байту составляющей цвета поставим в соответствие 8 байт для PWM-последовательности. На неё же можно наложить Гамма-коррекцию. Как представил, как эти таблицы на Си генерить... Да ещё надо либо отдельно PWM и Гамма, либо одну PWM+Гамма. То есть, для универсальности три таблицы надо. Да ну на. Давайте сделаем почеловечески.
Спойлер

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

template<uint32_t N, bool GammaCorrection=true>
class COLOR2PWM
{
  uint64_t value[N]{};
  static inline constexpr uint8_t LEDGamma(uint8_t v) { return (v * v + v) >> 8; }
public:  
  constexpr COLOR2PWM()
   {
     for (uint32_t n = 0; n < N; n++)
       for (uint32_t i = 0; i < 8; i++)
         value[n] += (GammaCorrection ? LEDGamma(n) : n) & 1<<(7-i) ? (uint64_t)TIM_HI<<i*8 : (uint64_t)TIM_LO<<i*8;
   }
   constexpr uint64_t operator()(uint8_t n) const { return value[n]; }
};

constexpr COLOR2PWM<256> color2pwm;

struct RGB
{
  uint8_t g;
  uint8_t r;  
  uint8_t b;
};

struct PWM_RGB_BUF
{
  uint64_t g; 
  uint64_t r; 
  uint64_t b;

  inline PWM_RGB_BUF& operator=(RGB rgb)
  {
    this->g = color2pwm(rgb.g);
    this->r = color2pwm(rgb.r);    
    this->b = color2pwm(rgb.b);
    return *this;  
  }  
  
};

PWM_RGB_BUF dma_pwm_buf[16];
RGB leds[16] = { {0x12, 0x34, 0x56}, {0x78, 0x9A, 0xBC}, {0x00, 0x00, 0x00} };
Собственно и всё. Таблица посчитается на этапе компиляции и ляжет во flash. Причём, хочешь с гамма-кореккцией, хочешь без совершенно бесплатно.

Замер скорости преобразования одного диода 0.67 мкс, а восьми диодов 5,9 мкс.

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

TEST_PIN::set();
for(uint32_t i=0; i<8; i++) 
  dma_pwm_buf[i] = leds[i]; //Тут скрыто идёт преобразование
TEST_PIN::clear();
С такой скоростью уже можно не создавать pwm-буфер для всей ленты, который жирноватый получается, а преобразовывать в прерывании по несколько диодов.

Ну и включим DMA+PWM, не зря же клаву топтали. :)
СпойлерИзображение
DS2_2020103174841.png
(40.02 КБ) 84 скачивания
Для особо любознательных расскажу, что если использовать "константный диод", то даже таблица кодировки не будет использоваться. Компилятор просчитает всё без неё и будет ещё быстрее. К примеру, вот этот код всего 0,34 мкс для одного и 1,9 мкс для восьми диодов выполняется.

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

constexpr RGB green_led = {0x80,0,0};

for(uint32_t i=0; i<8; i++) 
  dma_pwm_buf[i] = green_led;

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

dma_pwm_buf[0] = green_led;  
        LDR      R3,??DataTable1_1
        ADR      R0,??DataTable1_2
        LDM      R0,{R0,R1}
        STM      R3!,{R0,R1}
        SUBS     R3,R3,#+8
        MOV      R0,R1
        MOVS     R5,R3
        ADDS     R5,R5,#+8
        STM      R5!,{R0,R1}
        MOVS     R5,R3
        ADDS     R5,R5,#+16
        STM      R5!,{R0,R1}
Реклама
Эиком - электронные компоненты и радиодетали
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Я только одного не понял: кому надо выводить на светодиоды константную картинку? Хорошо бы поглядеть на объем и быстродействие кода, который реализует динамическое изменение цветов светодиодов. И с учетом того, что пока предыдущий "кадр" не ушел, менять массив "картинки" нельзя.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="ARV",url="/forum/viewtopic.php?p=3916089#p3916089"]Я только одного не понял: кому надо выводить на светодиоды константную картинку? Хорошо бы поглядеть на объем и быстродействие кода, который реализует динамическое изменение цветов светодиодов.[/uquote]
Речь о скорости заполнения буфера. На входе цвета в RGB, можно проверять каждый бит цвета и копировать нужный байт, а можно для каждого из 3-х байт скопировать из таблицы 64-х битное значение, на ARM само копирование - одна инструкция выполняемая за 2 или 3 такта. А далее из таблицы данные выводит DMA, т.е. практически все время можно потратить на получение этих самых RGB.
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

я и не сомневаюсь, что все это МОЖНО. вопрос был в том - так ли компактно и быстро все это будет? речь шла о том, как constexpr позволяет получать компактный код... не уверен, что для обработки массивов в ОЗУ constrexpr даст выигрыш. вот и спросил.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

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

Сообщение Reflector »

[uquote="ARV",url="/forum/viewtopic.php?p=3916106#p3916106"]вопрос был в том - так ли компактно и быстро все это будет? речь шла о том, как constexpr позволяет получать компактный код... не уверен, что для обработки массивов в ОЗУ constrexpr даст выигрыш. вот и спросил.[/uquote]
Еще раз, речь про таблицу перекодировки, она генерится на этапе компиляции и ложится во флеш, с тем же успехом можно сгенерить ее отдельно и вставить в проект, но т.к. таблиц может быть несколько, то это менее удобно. У меня в эмуле спектрума раньше было 3 файла на C# для генерации больших таблиц, теперь их нет и компилируется даже быстрее. И подход там практически идентичный, нужно из байта пикселей и байта цвета получить 16 байт где каждому биту соответствует 2 байта цвета. На скорость выполнения влияет сам табличный подход, С++ лишь позволяет нужные таблицы получать относительно просто.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

ничего не понял... туповат-с.
1. есть экранная область пикселов rgb_t scr[] (где rgb_t - структура из 3 байт, определяющих цвет пиксела). то есть я написал scr[12] = {0xFF,0,0}; и 12-й светодиод засветился красным. как происходит работа через DMA с этим массивом при его выводе?
2. есть экранная область пикселов uint8_t scr[], в которой каждый пиксел определяется одним байтом, а значение этого байта есть индекс цвета в статической (flash) таблице "палитры" rgb_t palette[256];. т.е. я написал scr[12]=22; и 12-й светодиод засветился 22-ым цветом по палитре. как в этом случае работает DMA?

можете пояснить алгоритмы поведения МК в этих двух типичных случаях? что там и как перекодируется, откуда что берется и куда как выводится? и где кроется выигрыш и в чем именно он заключается?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

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

Сообщение Reflector »

[uquote="ARV",url="/forum/viewtopic.php?p=3916175#p3916175"]н1. есть экранная область пикселов rgb_t scr[] (где rgb_t - структура из 3 байт, определяющих цвет пиксела). то есть я написал scr[12] = {0xFF,0,0}; и 12-й светодиод засветился красным. как происходит работа через DMA с этим массивом при его выводе?[/uquote]
Сколько там у тебя максимум диодов? 254? По 30 us на диод получается 7.6 ms в течении которых проверяется каждый бит и нужный байт выводится через SPI, больше ничего в это время не делается. Если используется DMA, то можно относительно быстро получить для RGB 24 байта, скопировать их в промежуточный массив из которого данные выводит DMA. Это тоже можно сделать проверяя каждый бит и копируя байт или ничего не проверяя копировать за один раз из таблицы сразу 8 байт, что, по замерам VladislavS, в 4.5 раза быстрее. Размер промежуточный таблицы может быть какой угодно, хоть 24 байта для одного диода, даже в таком случае 29 us из 30-ти мк будет простаивать.
2. есть экранная область пикселов uint8_t scr[], в которой каждый пиксел определяется одним байтом, а значение этого байта есть индекс цвета в статической (flash) таблице "палитры" rgb_t palette[256];. т.е. я написал scr[12]=22; и 12-й светодиод засветился 22-ым цветом по палитре. как в этом случае работает DMA?
Какая разница палитра или не палитра, если в итоге для каждого диода будут получены цвета в RGB?
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

т.е. алгоритм такой:
1. первый старт DMA делается вручную: находим цвет первого светодиода, науськиваем DMA на этот цвет из 24 байт, стартуем DMA, который берет байт из буфера и пинает таймер, который формирует импульс, после чего процесс повторяется. я верно понял?
2. каждый последующий светодиод должен повторять п.1, но после того, как все 24 байта предыдущего отправлены. наверное, DMA может формировать прерывание по окончанию передачи буфера - вот в обработчик этого прерывания мы должны вычислить очередной адрес очередного светодиода, настроить DMA и т.д.
я верно описал общий принцип?

скажем, если поступить чуть иначе: настроить SPI на передачу первого байта в массиве, а по прерыванию от SPI просто беру следующий... и чем это хуже? одно периферийное устройтсво вместо 2... это на AVR так делать было опасно, потому что между байтами пауза могла возникнуть лишняя, а при быстродействии STM32 на это можно не обращать внимание...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

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

Сообщение Dimon456 »

И так, посчитаем затраты для 254 светиков:
2 кило флеша на таблицу
6 кило рам

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

Сообщение Reflector »

[uquote="ARV",url="/forum/viewtopic.php?p=3916197#p3916197"]я верно описал общий принцип?[/uquote]
У мелких STM32 по 4/6/8 КБ RAM, для 254 диодов нужен массив 254*3(если без палитры), таких массива можно выделить два, а промежуточный сделать, допустим, на два десятка диодов, итого потрачено 2КБ. Сначала отрабатывает скрипт заполняющий первый массив, затем заполняется промежуточный массив и запускается DMA, он работает непрерывно пока не передаст данные для всех диодов, при этом в середине каждой передачи вызывается прерывание в котором половина промежуточного массива дозаполняется новыми данными путем копирования 8-ми байтных фрагментов из таблицы. После включения DMA уже можно снова запускать скрипт который будет работать со вторым массивом, в итоге на сам вывод тратится около 200 us, если частота обновления 100 фпс, значит 9.8 ms из 10-ти можно отдать скриптовому движку...
скажем, если поступить чуть иначе: настроить SPI на передачу первого байта в массиве, а по прерыванию от SPI просто беру следующий... и чем это хуже? одно периферийное устройтсво вместо 2... это на AVR так делать было опасно, потому что между байтами пауза могла возникнуть лишняя, а при быстродействии STM32 на это можно не обращать внимание...
Для F0 только на вход в прерывание придется потратить 17-18 тактов, суммарно выйдет тактов 50 на каждый бит, примерно столько будет с DMA для всех 24-х бит.
Последний раз редактировалось Reflector Сб окт 31, 2020 16:05:24, всего редактировалось 2 раза.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Откуда 6 кб RAM то? Чтобы хранить состояние 254 rgb диодов надо 254*3 байт. Лучше сразу 254*4, так как выравнивание и диоды rgbw бывают. DMA буфер можно штук на 8 сделать. Да хоть на 2, проц стоит. То есть, ещё сотня-другая байт. Итого, в пределе в 1 кб влазим.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Reflector, вы опять за свое.
Еще раз, по вашему, хорошо, берем половину: 24 * 127 (половина светиков) = 3 кило рам.
Не влазит в F0.

Уменьшаем 24*63 = 1,5 кило рам.
+светики 254*3=762 рам.
Итог 2,3 кило рам. Влазит в F0.

И получилось 254/63 = 4 куска, стоит игра свеч? много можно сделать? когда очередной кусок заполнять? в прерывании дма или еще где?

VladislavS, вы правы, у меня дма буфер всего 24 байта.
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3916214#p3916214"]Reflector, вы опять за свое.
Еще раз, по вашему, хорошо, берем половину: 24 * 127 (половина светиков) = 3 кило рам.
Не влазит в F0.[/uquote]
Я не знаю откуда ты это берешь, написано было, что потрачено 2КБ и это с двумя буферами...
254*3 + 254*3 + 20*24 = 2004 байт

Половина RAM самого простого STM32F0, при этом второй буфер не обязателен, но с ним быстрее и проблем меньше(применительно к проекту ARV со скриптами), промежуточный буфер тоже не обязан быть именно на 20 диодов...
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Reflector писал(а):20*24
так, буфер на 20 светиков, ну где будем его заполнять? видать будем заполнять половинками? и наверное в прерывании дма?
Reflector писал(а):применительно к проекту ARV со скриптами
а применительно к этому проекту я могу задать всего 1 светик и работать с ним.
За чем мне тогда буфер дма 20*24?
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Если у тебя мало КЦ есть, то ты должен часто в прерывании DMA приседать, чтобы данные отправить. Если у тебя много КЦ есть, то можно включить DMA один раз и не думать о нём больше вообще, никогда!

Вот где вы в самый разгар 21-го века контроллеры без RAM берёте?
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3916230#p3916230"]так, буфер на 20 светиков, ну где будем его заполнять? видать будем заполнять половинками? и наверное в прерывании дма?[/uquote]
Заполнять половинками в прерывании, написано ведь уже!
Dimon456 писал(а):а применительно к этому проекту я могу задать всего 1 светик и работать с ним.
За чем мне тогда буфер дма 20*24?
А зачем я тогда говорил, что:
Размер промежуточный таблицы может быть какой угодно, хоть 24 байта для одного диода.
Хватает тебе такого буфера, какие проблемы... Можно и без прерываний обойтись, но что если мк решит подгрузить часть скрипта в буфер, а это далеко не самый быстрый процесс? А если прерывания таки используются, то чем они реже, тем меньше накладные расходы, но больше расход памяти. В зависимости от проекта и используемого мк конфигурируем размеры буферов наиболее оптимальным образом.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

VladislavS, а контроллеры с рам дорого стоят, и много слишком ног у них и грамотную плату для них надо, а не макетку.
Reflector, вот и выдайте миру свою версию "плеера", а меня текущая версия полностью устраивает.
По чему вы свои идеи перекладываете на других? Это же ваша идея, ну покажите, что может этот чип.
Ответить

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