SPI DMA функции

Стивестронг
Вторник, 1 мая 2018 г., 18:28
Я переработал функции SPI DMA:
https: // github.com/stevstrong/arduino_s ... 9bad4f52de

Изменения:
- Некоторые очистки + оптимизации
- Добавлены дополнительные флаги, чтобы обеспечить более гибкое использование (E.глин. Круглый режим, прерывание на половине передачи, асинхронный режим)
- Добавлена ​​дополнительная функция для DMASEND/DMATRANSFER для отправки отдельных данных вместо буфера - таким образом, код стал проще
- dmasendasync () теперь устарел, потому что асинхровый режим теперь поддерживается функцией dmasend ()
- ISR всегда запускается в конце передачи DMA, DMA останавливается только в круговой режиме
- Обратная совместимость гарантирована.

Это стало возможным написать простое приложение рабов с помощью: //----------------------------------------------------------------------------- void SPI_DMA_Rx_ISR(uint32_t trxComplete) { if (trxComplete) { dma_irq_full_complete = 1; } else { dma_irq_half_complete = 1; } } //----------------------------------------------------------------------------- void SPI_Setup(void) { // setup variables dma_irq_full_complete = 0; dma_irq_half_complete = 0; for (uint8_t i = 0; i

victor_pv
Вторник, 1 мая 2018 г., 19:52
Отлично, я сделаю это с парой набросков, когда у меня появится шанс.

Стивестронг
Ср. 02 мая 2018 г., 22:17
У меня сейчас забавная ситуация.

Я сделал простой набросок для тестирования SPI1 и SPI2 на том же чипе.
Вывод SPI2, работающий как Master, подключен к SPI1, работающий как раб.

SPI - это дефолт, объявленный в SPI.CPP как SPI (1).
Эскиз не объявляет никакого второго экземпляра для SPI2.
Это означает, что указатель экземпляра класса _spi2_this = 0.

Тем не менее, функция обратного вызова событий SPI2 void _spi2EventCallback() { reinterpret_cast(_spi2_this)->EventCallback(2); }

victor_pv
Чт, 3 мая 2018 12:50
Я не могу ответить на работу нулевого указателя, но об остальном имеет смысл для меня. Поскольку вы перенесли ISR, чтобы стать частью настройки, имеет смысл просто сохранить 1 указатель на класс и использовать настройки, как вы делаете.
Я думаю, что это также может решить проблему, упомянутую в обсуждении GitHub, о наличии проблем с функциями обратного вызова при использовании SetModule (), вы проверяли это?

Кроме того, мы могли бы сделать это статичным, а не правильно иметь один на объект? Поскольку он принимает порт SPI в качестве параметра, я не вижу точки, имеющего несколько копий этого. void SPIClass::EventCallback(uint16_t spi_num)

Стивестронг
Чт, 3 мая 2018 12:59
Я протестировал как с использованием setModule (), так и/или объявления отдельного класса для SPI2. Оба работают нормально.

Хорошо, я постараюсь сделать также статический обработчик событий.

Стивестронг
Пт, 04 мая 2018 11:38
Да, статический обработчик событий работает.
Мне пришлось объявить переменные Spisettings, используемые в обработчике как общественность, но тогда это работает.

Кроме того, я реализовал не DMA-функции для буферов 8 и 16 битов, включая версию для передачи отдельных данных вместо буфера.
https: // github.com/stevstrong/arduino_s ... FD0D1869EA

Измерено: для переноса 50 байтов из 8 -битного буфера занимает 5 мкс меньше, чем эквивалент DMA.
Это связано с накладными расходами на установку DMA, которая занимает 10 мкс.

victor_pv
Пн, 7 мая 2018 г., 4:40
Хороший.
У меня не было времени в эти выходные, но я планирую проверить ваши изменения, как только у меня есть момент с парой набросков, которые используют 2 порта SPI.

Я добавляю этот комментарий в коммит:
"Можем ли мы переименовать EventCallback в SpieventCallback?
Поскольку эта функция является статикой, мы избегаем риска, если где -то в какой -то другой библиотеке или на чьем -либо эскизе есть функция, называемая EventCallback."

Racemaniac
Пн, 7 мая 2018 г. 8:08
Звучит великолепно, счастлив видеть, как DMA улучшается, как это :).

Стивестронг
Пн, 7 мая 2018 г., 9:54
И все еще улучшается ;)

Добавлены некоторые новые функции, которые делают использование SPI действительно простым, как в режиме Master, так и в рабском режиме (локальная версия, под тестированием)

void dmatransferinit (const void *txbuf, void *rxbuf, uint16 длина, флаги Uint16)
void dmatransferinit (const uint16 tx_data, void *rxbuf, uint16 длина, флаги Uint16)
- вызвано во время настройки, чтобы инициировать передачу, не запустив ее. Эквивалент предыдущего dmatransferset (...). Установит большинство параметров DMA.
- Длина и флаги (асинхронность) будут храниться в настройках для последующего использования.

Флаги:
- DMA_HALF_TRNS - будет вызывать функцию обратного вызова. Пользовательский обратный вызов имеет входной параметр, который покажет, является ли IRQ для половины или полной передачи.
- DMA_CIRC_MODE - установит DMA в круглом режиме. Очень полезен в режиме рабов, но и в главном режиме: в сочетании с полуперносили.
- DMA_ASYNC - Установите, если вы хотите начать перенос, не ожидая его конца. Полезно в подчиненном режиме в сочетании с предыдущими флагами, но также выгодно в главном режиме. Пользователь должен позаботиться о том, чтобы в главном режиме SS PIN должен быть деактивирован только в конце передачи (обнаруживается через обратный вызов пользователя или любую другую функцию утилиты ниже)

void dmatransfer (void)
- Начнет перевод, будучи эквивалентным предыдущего dmatransferrepeat (). Используется вместе с dmatransferinit. Берет ранее сохраненную длину и асинхровый флаг. Можно называться повторяющимся после того, как данные были изменены/обработаны в не циркулярном режиме.

uint16 dmatransferremaining ()
- Возвращает оставшееся количество байтов/слов, которые будут переданы. Полезно, например, в рабов 8-) ) или никакого обратного вызова пользователя не было прикреплено.

uint8 dmatransferreedy ()
- Возврат 1, если передача завершена, в противном случае 0. Полезно, если пользователь не подключил какую -либо функцию обратного вызова.


Идентичные функции, добавленные для dmasend..., При этом функция dmasend () имеет вариант, в котором пользователь может запустить передачу, указав адрес TXBuffer, остальные параметры DMA остаются неизменными по сравнению с init:
void dmasend (const void *txbuf)
void dmasend (const uint16 tx_data)


Любые комментарии/пожелания?

AG123
Вторник 8 мая 2018 12:43
+1 я бы просто хотел бы, чтобы у меня было больше времени, чтобы играть с этим, в любом случае, большое спасибо за все это :ржу не могу:

Мадиас
Вторник 8 мая 2018 г. 22:11
Есть две настоящие «убийственные функции» для STM32Duino (Rogers Core):
  • Этот DMA функционирует
  • Библиотека USB-Hid

Я думаю, что ни один другой *** Duino не может предоставить это таким простым способом ;)

ОК, получил третий: загрузчик (ы)

victor_pv
Ср 9 мая 2018 г., 3:09
Стив, у вас есть новые изменения в некоторых коммита?
Я проверил тот, который в первом посте и не вижу этих последних изменений.

Стивестронг
Ср. 09 мая 2018 г. 8:13
Я проверил вчера и сделал несколько исправлений, я сделаю их сегодня.

Стивестронг
Ср 9 мая 2018 г., 20:03
Я совершил изменения, смотрите здесь: https: // github.com/stevstrong/arduino_s ... E73A693D93

Обратная совместимость поддерживается для всех функций, используемых в настоящее время в репо.
Описание новых функций можно найти здесь: ViewTopic.PHP?f = 9&T = 3556#P44922

Я прикрепляю два тестовых наброска для двух синих таблеток.
Один Мастер и один раб, Мастер отправляет буфер над SPI2 в раб и получает его на две части над SPI1 от раба.
Используемые часы SPI составляют 18 МГц для обоих портов.

С 36 МГц на SPI1 у меня есть некоторые проблемы, придется проанализировать ситуацию. Я помню, как Виктор проверял больше времени назад функционирует DMA и наблюдал аналогичную проблему, так что это может быть проблема HW.

victor_pv
Ср 09 мая 2018 г., 20:14
[Стивестронг - Ср 09 мая 2018 г., 20:03] - С 36 МГц на SPI1 у меня есть некоторые проблемы, придется проанализировать ситуацию. Я помню, как Виктор проверял больше времени назад функционирует DMA и наблюдал аналогичную проблему, так что это может быть проблема HW.
Правильный. Мой тест был проведен с одним портом с одним буфером TX и одним буфером RX.
Используемая функция dmatransfer, а при 36 МГц RX потеряет несколько байтов (так что RX DMA не будет завершено несколько раз). На 18 МГц все будет хорошо.
Я загрузил буфер TX со значениями, затем сравнивал с буфером RX, и потерянные байты не всегда будут в одних и тех же положениях или одинаково их число. Я подозреваю, что на 36 МГц у периферийного устройства SPI возникает некоторая проблема, и либо данные каким -то образом не загружаются в DR из регистра внутреннего сдвига, либо загружается, но запрос DMA не генерируется, или, возможно, не обслуживается вовремя, прежде чем следующие данные перезаписывают предыдущие один. Я не помню, проверю ли я когда -нибудь флаг переполнения.
Можно также быть связано с тем, что здесь и тест не пропустили несколько битов, я не могу вспомнить, насколько скрипкой были данные RX (если пропустить целые байты или выглядели так, будто некоторые биты были потеряны, и, таким образом, биты из следующего байта завершены предыдущим).
Я проверил установление приоритета RX DMA для самого высокого и приоритета TX до самого низкого и до сих пор не мог предотвратить проблему. Единственный способ предотвратить его во время моего теста - запустить порт при 18 МГц. Я использовал короткий кабель между булавками MOSI и мисо (10 см или меньше)
Поскольку 36 МГц не в состоянии, в какой -то момент я просто решил перестать смотреть на него и двигаться дальше.

Пито
Чт 10 мая 2018 г. 11:10
Но наши SDCards работали на 36 МГц в прошлом. Почему?

victor_pv
Пт 11 мая 2018 г. 15:27
[Пито - Чт 10 мая 2018 г. 11:10] - Но наши SDCards работали на 36 МГц в прошлом. Почему?
Я не могу сказать наверняка, возможно, потому, что SDCARDS не используют TX и RX одновременно?
Мы используем передачу DMA, но он неоднократно передает 0xff, возможно, вмешательство от отправки 0s и 1s на высокой скорости вызывает проблемы, которые не наблюдаются при последовательности высокого уровня? или, возможно, связан с увеличением указателя памяти DMA TX? (В переносе SDCARD установлено, что не увеличивается).

Стивестронг
Пн 14 мая 2018 г., 16:14
Я скорее думаю, что это проблема HW.
Он идет не так, когда порт 1 с 36 МГц передает данные одновременно с портом 2 (любая частота).
Порты 1 и 2 одновременно при 18 МГц в порядке.
Порт 1 один @36 МГц в порядке.

C_D
Чт 31 мая 2018 г., 20:30
Ваше время идеальное, я собираюсь начать проект с помощью DMA и SPI, поэтому я собираюсь хорошо прочитать ваш код.

Я предполагаю, что пример наброска, который вы разместили, работает нормально? Я попробовал это вчера вечером и получал ошибки данных, но это может быть моя проводка, вызывающая проблемы, так как это было только на макете. Я предполагаю, что два перевода предназначены для отправки 0-49, а затем 50-99 каждый раз?

Когда я запустил код, я получу несколько хороших переводов, а затем, например, несколько плохих [0 1 2 3 4 5 6 7 8 9 10 11 12 197 45 86 203 ...] или это станет компенсированным несколькими персонажами и в конечном итоге получит [3 4 5 6 7 8 9 ... 49 50 51 52]

Убрать скорость SPI до 9 МГц, казалось, улучшила ситуацию, но я еще не исследовал дальше дальше.

РЕДАКТИРОВАТЬ:
Это была проводка. Снял макет с установки, и теперь он хорошо работает при 18 МГц 8-)

Стивестронг
Пт, 01 июня 2018 г. 13:15
Я рад, что это тоже работает для тебя. 8-)
[C_D - Четверг 31 мая 2018 г., 8:30 вечера] - Я предполагаю, что два перевода предназначены для отправки 0-49, а затем 50-99 каждый раз?
Да, действительно.
Текс буфер значений 0-99 передается многократно, что имеет одинаковый размер буфера RX.
Таким образом, RX ISR должен обнаружить половину трансфертов и полных переводов, а основной цикл должен печатать всегда идентичные данные 0-49 и 50-99.

Прогемем