Async (iSH) SPI.писать?

Хейсан
Сб, 04 августа 2018 г., 19:25
(Используя ядро ​​Роджера)

Играя сегодня, я заметил что -то довольно интересное:

В SPI_TX Libmaple: while ( (regs->SR & SPI_SR_TXE)==0 ) ; //while ( spi_is_tx_empty(dev)==0 ); // wait Tx to be empty regs->DR = *dp8++;

Стивестронг
Солнце 05 августа 2018 г., 6:36
Можете ли вы предоставить простой эскиз для тестирования?
Вы используете отдельные записи или буферированные (несколько) пишет?
Потому что использование буферированного записи SPI.Напишите (BUF, NR_BYTES) будет почти так же быстро, как и с DMA, для менее чем ~ 70 байтов даже быстрее, чем с DMA.

РЕДАКТИРОВАТЬ
Если вы обратитесь к этим строкам: https: // github.com/rogerclarkmelbourne/ ... #L107-L108
Это для буферированной записи, и они оптимизированы, чтобы не дождаться окончания последнего перенесенного байта.
Но ожидание последнего байта должно быть где -то там, и поэтому он переведен в SPI.CPP: https: // github.com/rogerclarkmelbourne/ ... #L357-L358.
Я действительно не вижу никаких проблем с этим.

Edit2
Я думаю, что вы смешали, один байт пишет с буферированной записи.
Ваш экстракт из SPI.C для одиночной записи: https: // github.com/rogerclarkmelbourne/ ... #L327-L328, Это вызывает (встроенную) функцию spi_tx_reg, не смешивать с spi_tx !!!

Хейсан
Солнце 05 августа 2018 10:37
Я буду войти и уйти в течение дня. Если мне удастся сесть достаточно долго, я подготовлю отдельный эскиз.

Вот где код предназначен для использования (добавлено в ADAFRIT_ILI9341_STM.час):
#ifdef _ADAFRUIT_FB_H_ void drawFB(int x, int y, Adafruit_FB1BPP& fb, uint16_t pal[]) { if(x < 0 || y < 0 || x + fb.fbwidth() > WIDTH || y + fb.fbheight() > HEIGHT) return; setAddrWindow(x, y, x + fb.fbwidth() - 1, y + fb.fbheight() - 1); int iy, ix; uint16_t p; int bp = 0; uint8_t m = 1; int ms = 0; for(iy = 0; iy < fb.fbheight(); iy++) { for(ix = 0; ix < fb.fbwidth(); ix++) { mSPI.writeAsync(pal[(fb.buffer[bp++] & m)>>ms]); } m <<= 1; ms++; if(m) { bp -= fb.fbwidth(); } else { m = 1; ms = 0; } } mSPI.writeAsyncEnd(); cs_set(); } #endif

Стивестронг
Солнце 05 августа 2018 11:08
Ваш код кажется разумным.
Я предполагаю, что Array Pal [] содержит значения Uint16, поэтому вы используете SPI в режиме 16 -битного режима, справа?

Вы можете немного ускорить код, если заявите функцию writeAsync () как «встроенный» в файле заголовка.

Хейсан
Солнце 05 августа 2018 11:25
[Стивестронг - Солнце 05 августа 2018 11:08] - Ваш код кажется разумным.
Я предполагаю, что Array Pal [] содержит значения Uint16, поэтому вы используете SPI в режиме 16 -битного режима, справа?

Вы можете немного ускорить код, если заявите функцию writeAsync () как «встроенный» в файле заголовка.
Спасибо - я еще не начал оптимизировать это. Это был быстрый хак, чтобы попытаться узнать, почему SPI.write () был таким медленным.

Мне было интересно, есть ли особая причина, по которой обертка Spiclass была написана таким образом, вместо того, чтобы использовать примитивы Libmaple (которые уже асинхронны)? Должен ли я потратить некоторое время на подготовку изменения в Spiclass или просто добавить отдельный класс асинхронных функций?

Хейсан
Солнце 05 августа 2018 11:27
В качестве примечания, рендеринг 240x240 инструменты типа набора теперь в 2 раза быстрее, чем рисунок непосредственно в библиотеку ILI9341, и Flicker Free ;) .

Стивестронг
Солнце 05 августа 2018 17:40
[Хейсан - Солнце 05 августа 2018 11:25] - Мне было интересно, есть ли особая причина, по которой обертка Spiclass была написана таким образом, вместо того, чтобы использовать примитивы Libmaple (которые уже асинхронны)? Должен ли я потратить некоторое время на подготовку изменения в Spiclass или просто добавить отдельный класс асинхронных функций?
Функции SPI LIB совместимы с Arduino, и я бы не предложил их изменить.
Ваше решение-нестандартная настройка, которая помогает в конкретной ситуации.
Как вы сами сказали, ваше заявление будет на самом деле хорошим кандидатом на двойную буферизованную передачу DMA.

Хейсан
Солнце 05 августа 2018 г. 20:56
[Стивестронг - Солнце 05 августа 2018 г., 17:40] - Функции SPI LIB совместимы с Arduino, и я бы не предложил их изменить.
Ваше решение-нестандартная настройка, которая помогает в конкретной ситуации.
Как вы сами сказали, ваше заявление будет на самом деле хорошим кандидатом на двойную буферизованную передачу DMA.
Spiclass.write () не является стандартной функцией ARDUINO API - она ​​имеет только Transfer (), которая по определению должно быть синхронным. Но я вижу, что изменение функции стандартного write () на самом деле не будет практичной - в различных библиотеках недостаточно дисциплины в вызове EndTransaction () - поэтому вывод данных не будет гарантировано при любых обстоятельствах.

В качестве альтернативы, что было бы вашими мыслями о перемещении _currentsetting от частного к защищенному, так что полученные классы можно сделать с помощью асинхронных функций? Я хотел бы избежать дополнительного штрафа памяти двух буферов DMA (особенно, когда возможный прирост производительности настолько мал), но я также не хочу, чтобы пользователям понадобилось пользовательское ядро ​​для создания приложения...

Спасибо,
Джастин

Хейсан
Ср 8 августа 2018 г., 21:21
Наконец -то поступил с этим еще немного, и я делаю некоторый прогресс.

Сначала примечание. Часы SPI 36 МГц - я.эн. 2 часа процессора за бит. SPI пишет ширину 16 бит. Таким образом, есть 32 часа процессора, чтобы сохранить буфер SPI полным. Если вы можете сделать это, то конечный результат будет быстрее и использовать меньше памяти, чем реализация DMA.

Проблема в том, что 32 часа не так много ;) .

В качестве ссылки я использую: tfto.fillRect(0,0,240,240,0);

Стивестронг
Чт 09 августа 2018 г. 5:05 утра
Использовать директиву компилятора «-O3».

Хейсан
Чт 9 августа 2018 г. 8:11
Спасибо «-O3», доставляет его до скорости DMA для всех случаев - за 10% вспышки.

Как ни странно, любые попытки местных оптимизаций, например: void __attribute__((optimize("O3"))) drawFB(int x, int y, Adafruit_FB& fb, uint16_t pal[]) {

Хейсан
Пт 17 августа 2018 г., 19:24
Я играл с этим еще немного, и мне все еще интересно...

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

Единственный способ получить реальное преимущество от DMA - это использовать dmasendasync, но текущий API не работает из библиотек, особенно если автобус обменивается.

По крайней мере, штат должен быть опробован в начале транзакции и эндранзакции, чтобы убедиться, что оно вернулось к SPI_STATE_READY (ASYNC TRANSFOR. Или это может быть сделано более прозрачным для разработчиков приложений путем проверки состояния на всех точках входа API.

Мнения?