Jump to content

    
Sign in to follow this  
DogPawlowa

Максимальное разрешение многоканального программного ШИМ на STM32

Recommended Posts

N 16 каналов

F Частота 400 Гц

n Количество градаций 1000

f Частота микроконтроллера 72 MHz

p Ресурсы времени на обслуживание ШИМ 50%

 

T Период прерывания обслуживания ШИМ = (1/(F*n)) = 1/(400*1000) = 2,5 мкс

Время прерывания 2,5 *50/100 = 1,25 мкс.

Допустимое количество команд 72*1,25= 90

 

Делаем тупо 16 раз:

 

if (count==pwm[NUM]) PORT->BSRR=PIN

 

На каждый канал тратится шесть команд, итого 96 команд плюс инкремент-пролог-эпилог.

Много. Плюс джиттер - отдельный вопрос.

 

Переделываем на предварительное формирование слова для записи в порт, и потом три записи этих байтов

4 команды на канал итого 64 плюс чистка и запись в три порта 11 команд всего 75.

Чуть лучше.

 

Какие еще варианты могут быть? (кроме снижения требований, конечно )

 

Сдвиговый регистр на SPI с записью по DMA? Что-то еще?

Share this post


Link to post
Share on other sites

Попробуй нечто в таком духе:

typedef struct {
    int count;
    unsigned mask;
} pwmchan_t;

pwmchan_t pwm_array[2][17];
int current_array;
int count;
unsigned mask;
    
    // прерывание

    // Вывести (приготовленную на прошлом заходе) маску в порт
    // Это минимизация джиттера
    PORT = mask;
    if( ++count == PERIOD) {
        count = 0;
        mask = 0;
        pwmptr = pwm_array[current_array];
    } else {
        while( count == pwmptr->count ) {    // тут было правильно, но ГЛУПО
            mask |= pwmptr->mask;        // видать, послобеденная полудрёма не дала
            ++pwmptr;                // нормально добавить обработку нескольких одинаковых
        }
    }

В массиве содержатся отсортированные по возрастанию count записи, при изменении

скважности какого-от канала массив пересортировывается во второй копии и делается

замена индекса current_array с 0 на 1 и назад

При желании можно замену current_array привязывать к окончанию периода - менять

current_array_next, а в обработчике прерывания по достижению PERIOD делать

current_array = current_array_next

Главное, чтобы обработчик успевал при самом худшем раскладе -

когда все каналы станут на одну скважность - уложиться в период (а не в половину).

Ну а загрузка процессора будет низкая, гораздо ниже половины (основная масса прерываний

будет отрабатывать быстро).

 

 

Да, совсем забыл. записей в массиве 17 для того, чтобы в последней записи держать такое значение .count, что оно не будет достигнуто счётчиком. Это чтобы if( count == pwmptr->count ) и аналогичное в while работало и как ограничитель инкремента указателя

Share this post


Link to post
Share on other sites
Попробуй нечто в таком духе:

Спасибо, идею понял.

Общее высвобождение ресурсов на порядок, но с худшим случаем нужно разбираться в симуляторе детально, что же там получается.

Share this post


Link to post
Share on other sites
Что-то еще?

Взять какую-нибудь тиню2313, в ней реализовать ШИМы на asm'е. (50 тактов на период, возможно хватит, на 8 каналов так точно хватит).

Передавать ей параметры ШИМа с частотой 400Гц, и пусть генерит с 99% ресурсом под ШИМ.

расширять будет легко, вдруг понадобится не 16, а 64-128 каналов, подключите еще n тинь и готово.

А STM пусть отдыхает :)

Share this post


Link to post
Share on other sites

А я не понял, заранее заготовленную колбасу размером 2000 байт (1000 полуслов) уже некуда положить? Зато времени свободного будет валом.

Share this post


Link to post
Share on other sites

Тьху, ну да. А можно и не всю колбасу, а только несколько нужных кусочков - т.е., как у меня, только после сортировки слить .mask с одинаковым .count и туда же добавить предыдущее .mask, укоротив рабочую часть массива и записать ограничитель в следующем элементе в .count. Максимальная длина будет такая, что влезет в данный массив, а (в исправленном) while(count == pwmptr->count) заменить назад на if без while - тело обработчика будет выполняться ощутимо дольше, чем для 2000-байтовой колбасы, но "худшего случая" просто не будет, тело будет всё равно достаточно быстрым.

Ну и будет не mask |= pwmptr->mask а mask = pwmptr->mask (см. про "добавить предыдущее"), ещё может малость сэкономит.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this