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

Добрый день, коллеги!

Есть связка на приём и передачу через 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. И чуть чаще на максимальном уровне оптимизации.

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


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

Сначал включаем канал приёма. Затем - канал передачи, и именно по нему ждём завершения транзакции. Подразумевается, что канал приёма их завершит тоже, т.к. шина SSP - синхронная.

Вроде как должно быть очевидным, что ждать завершения нужно по каналу приёма, но никак не передачи. :wacko:

 

Подразумевается, что канал приёма их завершит тоже, т.к. шина SSP - синхронная.

Шина синхронная и что с того? Данные на передачу надо сперва записать, а потом они начнут выдвигаться, а на приём наоборот - сперва вдвигаются, а потом появляются в регистре приёма.

 

Коллеги, я просто не понимаю источник ошибки, т.к. не один флаг не взводится. Флаги переполнения FIFO RX у SSP тоже обнулены. Из-за чего так может вести себя дмашник?

Как можно не понимать очевидного??? :wacko: Вы же сами пишете про FIFO.

Записали Вы в TX.FIFO последние данные - данных по TX у Вас больше нет, Вам приходит событие о завершении TX DMA-пересылки. Вы режете канал. А в это время SSP продолжает передачу из TX.FIFO находящихся там данных (ну и соответственно - приём в RX.FIFO).

Вроде должно быть очевидным, что работу с SSP нужно всегда завершать по завершению RX блока. Даже без FIFO.

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


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

Вроде должно быть очевидным, что работу с SSP нужно всегда завершать по завершению RX блока. Даже без FIFO.

ОК! Но почему же тогда это проявляется очень редко? И зависит от burst size? Я действительно не понимаю, возможно от сильной усталости... Спасибо! Завтра на работе попробую следовать вашему совету!

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


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

ОК! Но почему же тогда это проявляется очень редко? И зависит от burst size? Я действительно не понимаю, возможно от сильной усталости... Спасибо! Завтра на работе попробую следовать вашему совету!

Потому что выключаете SSP Вы видимо в ISR, который активизируется завершением DMA? Из-за задержки входа в ISR (наложения других более приоритетных ISR или участков с запрещёнными прерываниями), иногда все данные из TX.FIFO успевают уйти (а в RX - все прийти). На эту задержку будет влиять и оптимизация и размер burst.

Тогда, уменьшив SCLK, получите в среднем более частое возникновение бага.

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


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

Потому что выключаете SSP Вы видимо в ISR, который активизируется завершением DMA?

Я не выключаю SSP. SSP всегда включен. Перед транзакцией разрешатся всегда передача через DMA. А вот канал приёма DMA включатся только в том случае, если принятые данные нужны. Иногда же данные достаточно просто передать, а ничего вычитывать из слейва не требуется. В начале каждой транзакции через шину я вычитываю FIFO буфер SSP, т.к. там есть данные, если в предыдущей транзакции мы не использовали данные от слейва. Также очищаю флаг OVERRUN. В связи с этим понимаю, что зря NXP не сделала возможность отключить приёмник SSP. И всегда приходится вычитывать его FIFO.

Ну и включив передающий канал ДМА (предварительно включив, если требуется принимающий), я разу же жду события от прерывания TC (по передаче). Как только оно наступает, я читаю, что все транзакции на шине закончились.

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


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

Я не выключаю SSP. SSP всегда включен.

...

я разу же жду события от прерывания TC (по передаче). Как только оно наступает, я читаю, что все транзакции на шине закончились.

Под выключением я имел в виду вот именно это. Назовите это хоть остановом хоть ещё как.

Неправильно считаете. Прерывание об окончании передачи TX.DMA говорит только о том, что закончена передача данного блока DMA из памяти в целевую периферию (в целевой адрес периферии было записано последнее слово из FIFO DMA-канала). Вы же получаете прерывание о завершении от DMA, а не от SSP, с чего тогда Вы решили что SSP закончил свою работу???

Если Вы запишете слово в выходной TX-буфер SSP процессором без DMA, Вы тоже будете считать что передача по SPI закончилась в момент завершения выполнения команды записи?

Она ещё может даже не начаться. Точно так же - и в момент завершения передачи TX-DMA блока передача по SPI ещё может даже не начаться.

Поэтому судить можно только по завершению RX.DMA.

Именно поэтому и NXP не сделала отключения приёмника ибо - нафиг это не нужно. Потому что приёмный канал в любом случае нужен для нормального обнаружения завершения транзакции.

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


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

Она ещё может даже не начаться. Точно так же - и в момент завершения передачи TX-DMA блока передача по SPI ещё может даже не начаться.

Кажется начинаю понимать :rolleyes: Спасибо, вам, уважаемый jcxz! Завтра аппробирую! Лишь бы получилось!

 

З.Ы. Мне одному кажется, что из одного только юзер мануала на микроконтроллер не следует всего того, что вы сказали? Что это? Многолетний опыт работы с различными микроконтроллерами? Или я за соснами леса не вижу? :rolleyes:

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


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

З.Ы. Мне одному кажется, что из одного только юзер мануала на микроконтроллер не следует всего того, что вы сказали? Что это? Многолетний опыт работы с различными микроконтроллерами? Или я за соснами леса не вижу? :rolleyes:

Честно говоря - не знаю. Я конечно много лет работал с разными LPC - от LPC23xx (старых ещё), до LPC43xx. И ничего кроме мануалов на них не читал.

Но впрочем это ведь касается не только NXP: такой алгоритм работы, он справедлив для всех МК с SPI, везде аналогично - что у TI, что у STM, что у Infenion, .... Это вытекает из принципа работы самого SPI: чтобы что-то передать, надо вначале это что-то записать в буферный регистр, а чтобы что-то принять нужно сначала чтобы прошло нужное число клоков SCLK. Т.е. - события записи передаваемого слова в TX-буфер и появления принятого слова в RX-буфере - никак не могут быть одновременными явлениями. И FIFO тут не при чём.

Даже собственно на уровне одного бита - нужно его сперва выставить на шину и только потом - сэмплировать приёмником.

Поэтому и писал, что эти вещи мне кажутся очевидными.

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


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

Поэтому и писал, что эти вещи мне кажутся очевидными.

Чтож, я тоже для себя ещё сегодня утром думал, что SPI это что-то вроде сдвиговых регистров. Но не учёл некоторые моменты) ещё раз искренне благодарен!!!

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


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

Чтож, я тоже для себя ещё сегодня утром думал, что SPI это что-то вроде сдвиговых регистров. Но не учёл некоторые моменты) ещё раз искренне благодарен!!!

Пожалуйста. :)

И не забывайте про команды синхронизации шины (DMB/DSB) между записями в регистры DMA и регистры SSP и прочие периферийные регистры. Их отсутствие тоже иногда приводит к неожиданным эффектам. Особенно на таких довольно мощных МК с разными доменами тактирования как LPC43xx.

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


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

И не забывайте про команды синхронизации шины (DMB/DSB) между записями в регистры DMA и регистры SSP и прочие периферийные регистры.

Ну воот :smile3046: Про это мне совсем не известно... нужно, значит, ещё и команды дополнительные вставлять... если не сложно, можете чуть по-подробнее рассказать?

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


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

Ну воот :smile3046: Про это мне совсем не известно... нужно, значит, ещё и команды дополнительные вставлять... если не сложно, можете чуть по-подробнее рассказать?

Если Вы записали что-то в регистры некоей периферии, а затем - в регистры другой периферии. И вторая запись - запускает взаимодействие 2-й периферии с первой, то между первой записью и 2-й записью необходимо вставить DMB. Иначе будет то работать, то глючить.

Если к примеру какая-то запись в регистр периферии включает её работу, и эта периферия сразу посылает запрос DMA-каналу. А до этого вы конфигурили данный DMA-канал, и в процессе конфигурирования очистили регистр DMA-запросов, то возможна ситуация, что конфигурация DMA-канала запишется в него после того, как включится периферия его использующая. И например запрос к DMA от периферии потеряется и она вечно будет ждать обслуживания со стороны DMA-канала.

DMB устраняет эту проблему.

Ну или другой вариант: Вы в регистре флагов запросов прерываний некоей периферии почистили флажки, потом почистили их в NVIC (перед тем как размаскировать), а потом размаскировали данное прерывание в NVIC. И оно тут же произошло (прерывание). Хотя ещё никакой активности с периферией не было. Просто Ваша команда очистки флажков дошла до периферии позже чем команда очистки флажков в NVIC. И NVIC успел опять защёлкнуть запрос прерывания.

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


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

Если Вы записали что-то в регистры некоей периферии, а затем - в регистры другой периферии.

Вот и тема для моего лично роста)

 

Кстати, попробывал ожидать окончания транзакции по приёму - стало значительно лучше. Но вот с чистой передачей остаются проблемы. Приём мы не ведём. А как вы уже сказали, DMA при передаче лишь только отрапортует, что данные сброшены в регистры FIFIO, не более. Следовательно как гарантированно дождаться завершения именно передачи (без приёма) я пока не знаю. Прерывания от SSP соответствующих не нашёл(((

 

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


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

Следовательно как гарантированно дождаться завершения именно передачи (без приёма) я пока не знаю. Прерывания от SSP соответствующих не нашёл(((

Никак. Всегда программировать RX-DMA-канал.

Не понимаю - а зачем Вы упорно пытаетесь обойтись без приёма? 1 DMA канал сэкономить? Так их там много вроде. Пропускную способность шины сэкономить? Так её ещё постараться надо чтобы загрузить.

И приоритет RX-DMA-канала всегда должен быть выше чем у TX-DMA.

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


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

Никак. Всегда программировать RX-DMA-канал.

Не понимаю - а зачем Вы упорно пытаетесь обойтись без приёма? 1 DMA канал сэкономить?

Нет. Сложновато получается. Допустим, мне надо только передать 10 кб по связанному списку. Значит приём "холостых" байт нужно вести в какой-то закольцованный связным списком буфер?! Вот мне это и кажется избыточным. Видимо придётся делать.

И приоритет RX-DMA-канала всегда должен быть выше чем у TX-DMA.

Да-да, это я уже сделал)

 

Стоп!!! Это что же такое я говорю, совсем заработался. Не надо на приём делать холостой связный списко. Можно просто не инкрементировать адрес приёмника в дма, и лишь хоть весь объём Вселенной в буфер из одного байта))))))

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


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

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

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

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

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

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

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

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

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

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