Перейти к содержанию
    

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

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? Что-то еще?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В LPC2138 формирование ШИМ происходит аппаратно, но 16 каналов там не будет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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 работало и как ограничитель инкремента указателя

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Что-то еще?

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...