Мешает ли прямой доступ к порту ШИМ?

Думаю, я искал в SE вопросы о ШИМ, быстрой цифровой записи и т. д., но не нашел решения по этому вопросу.

Мне нужно использовать прямую запись на некоторые цифровые контакты. Некоторые контакты порта используют аналоговую запись/ШИМ, но не те контакты, к которым я обращаюсь в цифровом виде.

В функции digitalWrite ядро Arduino проверяет, используется ли ШИМ, и отключает его при попытке цифровой записи. Поскольку контакты здесь изолированы (цифровая запись на контакты ШИМ не осуществляется), необходим ли этот шаг?

Причина, по которой я спрашиваю, заключается в том, что при прямом доступе к порту, как в PORTD |= (PORTD & маска) | somebit, вы на самом деле записываете данные на контакты, используемые для ШИМ, вы просто не записываете измененные биты.

Я слишком много думаю об этом? Безопасно ли использовать прямые выходы порта на соседних выводах?

, 👍1

Обсуждение

Подсказка: почему бы не использовать для этого библиотеку? Например, https://github.com/mikaelpatel/Arduino-GPIO., @Mikael Patel

@MikaelPatel - я посмотрю на это, спасибо. Я не ожидаю, что там будет какое-то волшебство, но я всегда рад быть удивленным., @Jim Mack


1 ответ


Лучший ответ:

2

Прерывание таймера будет периодически переключать бит ШИМ и может делать это между чтением и записью вашего порта.

Простое решение — отключить прерывания на этапе чтения/изменения/записи в последовательности обновления порта. Это может привести к растягиванию цикла ШИМ. Если вы не выключите его, вы просто нарушите работу ШИМ, создав дополнительный короткий цикл. Какой из них хуже для вашего получателя ШИМ?

Лучшим решением может быть наблюдение за портом на предмет изменения бита ШИМ, а затем сразу же приступить к работе и обновить порт. Вы можете сделать это как блокирующим, так и неблокирующим способом.

Обновление:

Наблюдение за битами ШИМ кажется довольно медленным, что несколько противоречит цели прямой записи в порт.

Да, это далеко не идеально. Здесь есть компромисс. Сможет ли ваш потребитель ШИМ вместо этого терпеть потенциальные случайные сбои?

В целом, существует ряд причин для использования прямого ввода-вывода:

  • Меньший код;
  • Меньшая асимметрия ввода-вывода при наличии нескольких входов-выходов или нулевая асимметрия, если входы-выходы находятся в одном порту;
  • Меньше времени выполнения на критически важном пути;
  • Точное время вывода;

среди прочего. Ни в одном из этих случаев эти программные решения не помогут.

Можете ли вы переназначить свой выход на другой контакт другого порта, избежав всей этой проблемы? Это может быть лучше, чем любое из «решений». Добавление оборудования может привести к тому же результату — например, перенесению только ШИМ на ATtiny.

Обновление 2:

Кажется, это настолько встроено в структуру Arduino... не так ли? DigitalWrite() действительно преодолевает эту проблему?

Он «обращается» к этому — преодолевает его? Как это часто бывает, «это зависит».

Вот исходный код digitalWrite() из: /Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino /wiring_digital.c (на Mac; папка верхнего уровня). или два будут отличаться в Windows):

void digitalWrite(uint8_t pin, uint8_t val)
{
    uint8_t timer = digitalPinToTimer(pin);
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    volatile uint8_t *out;

    if (port == NOT_A_PIN) return;

    // Если вывод поддерживает выход ШИМ, нам нужно его отключить
    // перед цифровой записью.
    if (timer != NOT_ON_TIMER) turnOffPWM(timer);

    out = portOutputRegister(port);

    uint8_t oldSREG = SREG;
    cli();

    if (val == LOW) {
        *out &= ~bit;
    } else {
        *out |= bit;
    }

    SREG = oldSREG;
}

Обратите внимание, что прерывания сохраняются и восстанавливаются при чтении/изменении/записи регистра порта. Таким образом, digitalWrite() уже учитывает такую возможность. Этот метод растянет одну фазу случайного импульса ШИМ на несколько микросекунд.

В качестве альтернативы, игнорирование возможности столкновения и его возникновение кажется более серьезным: импульс может начаться или закончиться преждевременно. Для восстановления синхронизации потребуется больше времени (остальная часть нарушенной фазы).

Таким образом, критерием того, как управлять x, является вопрос: «Какой способ имеет меньшие или более приемлемые последствия для вашего потребителя ШИМ?»

,

Это имеет смысл, спасибо. Наблюдение за битами ШИМ кажется довольно медленным, что несколько противоречит цели прямой записи через порт. Мне придется подумать, какая из альтернатив хуже, как вы и просите., @Jim Mack

Спасибо за обновление. Я действительно стремлюсь к минимальному перекосу. Я не могу изменить используемые порты, они являются частью шилда. Поскольку эти ШИМ включены на 95-99%, я думаю, что риск сбоев достаточно низок, и я просто справлюсь. Любопытно, однако. Кажется, это настолько встроено в структуру Arduino... действительно ли digitalWrite() решает эту проблему?, @Jim Mack

Хорошая информация. Я вижу, что cli() и его друзья были бы в некоторой степени безопаснее, и фактически знание того, что PWM используется, устраняет необходимость сохранять и восстанавливать SREG (прерывания должны быть включены). Я также предполагаю, что если ШИМ находится на уровне 97%, вероятность того, что игнорирование прерываний приведет к значимому сбою, составляет всего 3%. Вздох. Думаю, я поэкспериментирую, когда у меня будет все оборудование., @Jim Mack