haker_fox 60 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба Добрый день, коллеги! Есть связка на приём и передачу через SSP + DMA в упомянутом микроконтроллере. В некоторый момент при тестировании обнаружил, что иногда канал DMA оставляет 4 непринятых байта в регистре CONTROL в поле size. При этом контроллер DMA не выставляет ни одного флага ошибки. Соответственно бит ENABLE этого канала остаётся в единице. Как устроены транзакции? Есть два канала dma. Канал 2 обслуживает передачу через SSP, канал 0 - приём через SSP (более приоритетный канал на приём). Далее, программируем одинаковое количество байт на передачу, соответственно и на приём тоже. Сначал включаем канал приёма. Затем - канал передачи, и именно по нему ждём завершения транзакции. Подразумевается, что канал приёма их завершит тоже, т.к. шина SSP - синхронная. В целом всё работает. Запускаю циклический тест (на шине висит флешка). Флешку пишу и читаю из неё. Соответственно адреса буферов всегда одни и теже. На 1000, скажем, транзакций в очень редких случаях происходит описанная проблема. Я уже умотался искать проблему. Несколько минимизировал её появление, установив burst size в 1 байт на приём и передачу. Если сделать 4 байта, то ошибка проявляется значительно чаще. Коллеги, я просто не понимаю источник ошибки, т.к. не один флаг не взводится. Флаги переполнения FIFO RX у SSP тоже обнулены. Из-за чего так может вести себя дмашник? Что особенно печалит: я не могу воспроизвести ошибку, и нет флагов ошибки... P.S. SSP - мастер. CS дёргаю программно, т.к. нужно выдерживать времянки. P.S.S. 4 байта остатка вовсе не обязательно. Сейчас поймал 3 и 7. P.S.S.S. Есть зависимость от оптимизации компилятора. Можно сказать, что ошибка не появляется, или слииишком редка, если оптимизация 0. И чуть чаще на максимальном уровне оптимизации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба Сначал включаем канал приёма. Затем - канал передачи, и именно по нему ждём завершения транзакции. Подразумевается, что канал приёма их завершит тоже, т.к. шина SSP - синхронная. Вроде как должно быть очевидным, что ждать завершения нужно по каналу приёма, но никак не передачи. Подразумевается, что канал приёма их завершит тоже, т.к. шина SSP - синхронная. Шина синхронная и что с того? Данные на передачу надо сперва записать, а потом они начнут выдвигаться, а на приём наоборот - сперва вдвигаются, а потом появляются в регистре приёма. Коллеги, я просто не понимаю источник ошибки, т.к. не один флаг не взводится. Флаги переполнения FIFO RX у SSP тоже обнулены. Из-за чего так может вести себя дмашник? Как можно не понимать очевидного??? Вы же сами пишете про FIFO. Записали Вы в TX.FIFO последние данные - данных по TX у Вас больше нет, Вам приходит событие о завершении TX DMA-пересылки. Вы режете канал. А в это время SSP продолжает передачу из TX.FIFO находящихся там данных (ну и соответственно - приём в RX.FIFO). Вроде должно быть очевидным, что работу с SSP нужно всегда завершать по завершению RX блока. Даже без FIFO. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба Вроде должно быть очевидным, что работу с SSP нужно всегда завершать по завершению RX блока. Даже без FIFO. ОК! Но почему же тогда это проявляется очень редко? И зависит от burst size? Я действительно не понимаю, возможно от сильной усталости... Спасибо! Завтра на работе попробую следовать вашему совету! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба ОК! Но почему же тогда это проявляется очень редко? И зависит от burst size? Я действительно не понимаю, возможно от сильной усталости... Спасибо! Завтра на работе попробую следовать вашему совету! Потому что выключаете SSP Вы видимо в ISR, который активизируется завершением DMA? Из-за задержки входа в ISR (наложения других более приоритетных ISR или участков с запрещёнными прерываниями), иногда все данные из TX.FIFO успевают уйти (а в RX - все прийти). На эту задержку будет влиять и оптимизация и размер burst. Тогда, уменьшив SCLK, получите в среднем более частое возникновение бага. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба Потому что выключаете SSP Вы видимо в ISR, который активизируется завершением DMA? Я не выключаю SSP. SSP всегда включен. Перед транзакцией разрешатся всегда передача через DMA. А вот канал приёма DMA включатся только в том случае, если принятые данные нужны. Иногда же данные достаточно просто передать, а ничего вычитывать из слейва не требуется. В начале каждой транзакции через шину я вычитываю FIFO буфер SSP, т.к. там есть данные, если в предыдущей транзакции мы не использовали данные от слейва. Также очищаю флаг OVERRUN. В связи с этим понимаю, что зря NXP не сделала возможность отключить приёмник SSP. И всегда приходится вычитывать его FIFO. Ну и включив передающий канал ДМА (предварительно включив, если требуется принимающий), я разу же жду события от прерывания TC (по передаче). Как только оно наступает, я читаю, что все транзакции на шине закончились. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба Я не выключаю SSP. SSP всегда включен. ... я разу же жду события от прерывания TC (по передаче). Как только оно наступает, я читаю, что все транзакции на шине закончились. Под выключением я имел в виду вот именно это. Назовите это хоть остановом хоть ещё как. Неправильно считаете. Прерывание об окончании передачи TX.DMA говорит только о том, что закончена передача данного блока DMA из памяти в целевую периферию (в целевой адрес периферии было записано последнее слово из FIFO DMA-канала). Вы же получаете прерывание о завершении от DMA, а не от SSP, с чего тогда Вы решили что SSP закончил свою работу??? Если Вы запишете слово в выходной TX-буфер SSP процессором без DMA, Вы тоже будете считать что передача по SPI закончилась в момент завершения выполнения команды записи? Она ещё может даже не начаться. Точно так же - и в момент завершения передачи TX-DMA блока передача по SPI ещё может даже не начаться. Поэтому судить можно только по завершению RX.DMA. Именно поэтому и NXP не сделала отключения приёмника ибо - нафиг это не нужно. Потому что приёмный канал в любом случае нужен для нормального обнаружения завершения транзакции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба Она ещё может даже не начаться. Точно так же - и в момент завершения передачи TX-DMA блока передача по SPI ещё может даже не начаться. Кажется начинаю понимать :rolleyes: Спасибо, вам, уважаемый jcxz! Завтра аппробирую! Лишь бы получилось! З.Ы. Мне одному кажется, что из одного только юзер мануала на микроконтроллер не следует всего того, что вы сказали? Что это? Многолетний опыт работы с различными микроконтроллерами? Или я за соснами леса не вижу? :rolleyes: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба З.Ы. Мне одному кажется, что из одного только юзер мануала на микроконтроллер не следует всего того, что вы сказали? Что это? Многолетний опыт работы с различными микроконтроллерами? Или я за соснами леса не вижу? :rolleyes: Честно говоря - не знаю. Я конечно много лет работал с разными LPC - от LPC23xx (старых ещё), до LPC43xx. И ничего кроме мануалов на них не читал. Но впрочем это ведь касается не только NXP: такой алгоритм работы, он справедлив для всех МК с SPI, везде аналогично - что у TI, что у STM, что у Infenion, .... Это вытекает из принципа работы самого SPI: чтобы что-то передать, надо вначале это что-то записать в буферный регистр, а чтобы что-то принять нужно сначала чтобы прошло нужное число клоков SCLK. Т.е. - события записи передаваемого слова в TX-буфер и появления принятого слова в RX-буфере - никак не могут быть одновременными явлениями. И FIFO тут не при чём. Даже собственно на уровне одного бита - нужно его сперва выставить на шину и только потом - сэмплировать приёмником. Поэтому и писал, что эти вещи мне кажутся очевидными. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба Поэтому и писал, что эти вещи мне кажутся очевидными. Чтож, я тоже для себя ещё сегодня утром думал, что SPI это что-то вроде сдвиговых регистров. Но не учёл некоторые моменты) ещё раз искренне благодарен!!! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба Чтож, я тоже для себя ещё сегодня утром думал, что SPI это что-то вроде сдвиговых регистров. Но не учёл некоторые моменты) ещё раз искренне благодарен!!! Пожалуйста. :) И не забывайте про команды синхронизации шины (DMB/DSB) между записями в регистры DMA и регистры SSP и прочие периферийные регистры. Их отсутствие тоже иногда приводит к неожиданным эффектам. Особенно на таких довольно мощных МК с разными доменами тактирования как LPC43xx. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба И не забывайте про команды синхронизации шины (DMB/DSB) между записями в регистры DMA и регистры SSP и прочие периферийные регистры. Ну воот :smile3046: Про это мне совсем не известно... нужно, значит, ещё и команды дополнительные вставлять... если не сложно, можете чуть по-подробнее рассказать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 13 февраля, 2018 Опубликовано 13 февраля, 2018 · Жалоба Ну воот :smile3046: Про это мне совсем не известно... нужно, значит, ещё и команды дополнительные вставлять... если не сложно, можете чуть по-подробнее рассказать? Если Вы записали что-то в регистры некоей периферии, а затем - в регистры другой периферии. И вторая запись - запускает взаимодействие 2-й периферии с первой, то между первой записью и 2-й записью необходимо вставить DMB. Иначе будет то работать, то глючить. Если к примеру какая-то запись в регистр периферии включает её работу, и эта периферия сразу посылает запрос DMA-каналу. А до этого вы конфигурили данный DMA-канал, и в процессе конфигурирования очистили регистр DMA-запросов, то возможна ситуация, что конфигурация DMA-канала запишется в него после того, как включится периферия его использующая. И например запрос к DMA от периферии потеряется и она вечно будет ждать обслуживания со стороны DMA-канала. DMB устраняет эту проблему. Ну или другой вариант: Вы в регистре флагов запросов прерываний некоей периферии почистили флажки, потом почистили их в NVIC (перед тем как размаскировать), а потом размаскировали данное прерывание в NVIC. И оно тут же произошло (прерывание). Хотя ещё никакой активности с периферией не было. Просто Ваша команда очистки флажков дошла до периферии позже чем команда очистки флажков в NVIC. И NVIC успел опять защёлкнуть запрос прерывания. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 14 февраля, 2018 Опубликовано 14 февраля, 2018 · Жалоба Если Вы записали что-то в регистры некоей периферии, а затем - в регистры другой периферии. Вот и тема для моего лично роста) Кстати, попробывал ожидать окончания транзакции по приёму - стало значительно лучше. Но вот с чистой передачей остаются проблемы. Приём мы не ведём. А как вы уже сказали, DMA при передаче лишь только отрапортует, что данные сброшены в регистры FIFIO, не более. Следовательно как гарантированно дождаться завершения именно передачи (без приёма) я пока не знаю. Прерывания от SSP соответствующих не нашёл((( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 14 февраля, 2018 Опубликовано 14 февраля, 2018 · Жалоба Следовательно как гарантированно дождаться завершения именно передачи (без приёма) я пока не знаю. Прерывания от SSP соответствующих не нашёл((( Никак. Всегда программировать RX-DMA-канал. Не понимаю - а зачем Вы упорно пытаетесь обойтись без приёма? 1 DMA канал сэкономить? Так их там много вроде. Пропускную способность шины сэкономить? Так её ещё постараться надо чтобы загрузить. И приоритет RX-DMA-канала всегда должен быть выше чем у TX-DMA. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
haker_fox 60 15 февраля, 2018 Опубликовано 15 февраля, 2018 · Жалоба Никак. Всегда программировать RX-DMA-канал. Не понимаю - а зачем Вы упорно пытаетесь обойтись без приёма? 1 DMA канал сэкономить? Нет. Сложновато получается. Допустим, мне надо только передать 10 кб по связанному списку. Значит приём "холостых" байт нужно вести в какой-то закольцованный связным списком буфер?! Вот мне это и кажется избыточным. Видимо придётся делать. И приоритет RX-DMA-канала всегда должен быть выше чем у TX-DMA. Да-да, это я уже сделал) Стоп!!! Это что же такое я говорю, совсем заработался. Не надо на приём делать холостой связный списко. Можно просто не инкрементировать адрес приёмника в дма, и лишь хоть весь объём Вселенной в буфер из одного байта)))))) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться