Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: LPC4337, DMA + SSP
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
haker_fox
Добрый день, коллеги!
Есть связка на приём и передачу через 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
Цитата(haker_fox @ Feb 13 2018, 11:08) *
Сначал включаем канал приёма. Затем - канал передачи, и именно по нему ждём завершения транзакции. Подразумевается, что канал приёма их завершит тоже, т.к. шина SSP - синхронная.

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

Цитата(haker_fox @ Feb 13 2018, 11:08) *
Подразумевается, что канал приёма их завершит тоже, т.к. шина SSP - синхронная.

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

Цитата(haker_fox @ Feb 13 2018, 11:08) *
Коллеги, я просто не понимаю источник ошибки, т.к. не один флаг не взводится. Флаги переполнения FIFO RX у SSP тоже обнулены. Из-за чего так может вести себя дмашник?

Как можно не понимать очевидного??? wacko.gif Вы же сами пишете про FIFO.
Записали Вы в TX.FIFO последние данные - данных по TX у Вас больше нет, Вам приходит событие о завершении TX DMA-пересылки. Вы режете канал. А в это время SSP продолжает передачу из TX.FIFO находящихся там данных (ну и соответственно - приём в RX.FIFO).
Вроде должно быть очевидным, что работу с SSP нужно всегда завершать по завершению RX блока. Даже без FIFO.
haker_fox
QUOTE (jcxz @ Feb 13 2018, 18:52) *
Вроде должно быть очевидным, что работу с SSP нужно всегда завершать по завершению RX блока. Даже без FIFO.

ОК! Но почему же тогда это проявляется очень редко? И зависит от burst size? Я действительно не понимаю, возможно от сильной усталости... Спасибо! Завтра на работе попробую следовать вашему совету!
jcxz
Цитата(haker_fox @ Feb 13 2018, 14:30) *
ОК! Но почему же тогда это проявляется очень редко? И зависит от burst size? Я действительно не понимаю, возможно от сильной усталости... Спасибо! Завтра на работе попробую следовать вашему совету!

Потому что выключаете SSP Вы видимо в ISR, который активизируется завершением DMA? Из-за задержки входа в ISR (наложения других более приоритетных ISR или участков с запрещёнными прерываниями), иногда все данные из TX.FIFO успевают уйти (а в RX - все прийти). На эту задержку будет влиять и оптимизация и размер burst.
Тогда, уменьшив SCLK, получите в среднем более частое возникновение бага.
haker_fox
QUOTE (jcxz @ Feb 13 2018, 20:38) *
Потому что выключаете SSP Вы видимо в ISR, который активизируется завершением DMA?

Я не выключаю SSP. SSP всегда включен. Перед транзакцией разрешатся всегда передача через DMA. А вот канал приёма DMA включатся только в том случае, если принятые данные нужны. Иногда же данные достаточно просто передать, а ничего вычитывать из слейва не требуется. В начале каждой транзакции через шину я вычитываю FIFO буфер SSP, т.к. там есть данные, если в предыдущей транзакции мы не использовали данные от слейва. Также очищаю флаг OVERRUN. В связи с этим понимаю, что зря NXP не сделала возможность отключить приёмник SSP. И всегда приходится вычитывать его FIFO.
Ну и включив передающий канал ДМА (предварительно включив, если требуется принимающий), я разу же жду события от прерывания TC (по передаче). Как только оно наступает, я читаю, что все транзакции на шине закончились.
jcxz
Цитата(haker_fox @ Feb 13 2018, 14:53) *
Я не выключаю SSP. SSP всегда включен.
...
я разу же жду события от прерывания TC (по передаче). Как только оно наступает, я читаю, что все транзакции на шине закончились.

Под выключением я имел в виду вот именно это. Назовите это хоть остановом хоть ещё как.
Неправильно считаете. Прерывание об окончании передачи TX.DMA говорит только о том, что закончена передача данного блока DMA из памяти в целевую периферию (в целевой адрес периферии было записано последнее слово из FIFO DMA-канала). Вы же получаете прерывание о завершении от DMA, а не от SSP, с чего тогда Вы решили что SSP закончил свою работу???
Если Вы запишете слово в выходной TX-буфер SSP процессором без DMA, Вы тоже будете считать что передача по SPI закончилась в момент завершения выполнения команды записи?
Она ещё может даже не начаться. Точно так же - и в момент завершения передачи TX-DMA блока передача по SPI ещё может даже не начаться.
Поэтому судить можно только по завершению RX.DMA.
Именно поэтому и NXP не сделала отключения приёмника ибо - нафиг это не нужно. Потому что приёмный канал в любом случае нужен для нормального обнаружения завершения транзакции.
haker_fox
QUOTE (jcxz @ Feb 13 2018, 21:19) *
Она ещё может даже не начаться. Точно так же - и в момент завершения передачи TX-DMA блока передача по SPI ещё может даже не начаться.

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

З.Ы. Мне одному кажется, что из одного только юзер мануала на микроконтроллер не следует всего того, что вы сказали? Что это? Многолетний опыт работы с различными микроконтроллерами? Или я за соснами леса не вижу? rolleyes.gif
jcxz
Цитата(haker_fox @ Feb 13 2018, 15:25) *
З.Ы. Мне одному кажется, что из одного только юзер мануала на микроконтроллер не следует всего того, что вы сказали? Что это? Многолетний опыт работы с различными микроконтроллерами? Или я за соснами леса не вижу? rolleyes.gif

Честно говоря - не знаю. Я конечно много лет работал с разными LPC - от LPC23xx (старых ещё), до LPC43xx. И ничего кроме мануалов на них не читал.
Но впрочем это ведь касается не только NXP: такой алгоритм работы, он справедлив для всех МК с SPI, везде аналогично - что у TI, что у STM, что у Infenion, .... Это вытекает из принципа работы самого SPI: чтобы что-то передать, надо вначале это что-то записать в буферный регистр, а чтобы что-то принять нужно сначала чтобы прошло нужное число клоков SCLK. Т.е. - события записи передаваемого слова в TX-буфер и появления принятого слова в RX-буфере - никак не могут быть одновременными явлениями. И FIFO тут не при чём.
Даже собственно на уровне одного бита - нужно его сперва выставить на шину и только потом - сэмплировать приёмником.
Поэтому и писал, что эти вещи мне кажутся очевидными.
haker_fox
QUOTE (jcxz @ Feb 13 2018, 21:45) *
Поэтому и писал, что эти вещи мне кажутся очевидными.

Чтож, я тоже для себя ещё сегодня утром думал, что SPI это что-то вроде сдвиговых регистров. Но не учёл некоторые моменты) ещё раз искренне благодарен!!!
jcxz
Цитата(haker_fox @ Feb 13 2018, 16:03) *
Чтож, я тоже для себя ещё сегодня утром думал, что SPI это что-то вроде сдвиговых регистров. Но не учёл некоторые моменты) ещё раз искренне благодарен!!!

Пожалуйста. sm.gif
И не забывайте про команды синхронизации шины (DMB/DSB) между записями в регистры DMA и регистры SSP и прочие периферийные регистры. Их отсутствие тоже иногда приводит к неожиданным эффектам. Особенно на таких довольно мощных МК с разными доменами тактирования как LPC43xx.
haker_fox
QUOTE (jcxz @ Feb 13 2018, 22:19) *
И не забывайте про команды синхронизации шины (DMB/DSB) между записями в регистры DMA и регистры SSP и прочие периферийные регистры.

Ну воот smile3046.gif Про это мне совсем не известно... нужно, значит, ещё и команды дополнительные вставлять... если не сложно, можете чуть по-подробнее рассказать?
jcxz
Цитата(haker_fox @ Feb 13 2018, 16:34) *
Ну воот smile3046.gif Про это мне совсем не известно... нужно, значит, ещё и команды дополнительные вставлять... если не сложно, можете чуть по-подробнее рассказать?

Если Вы записали что-то в регистры некоей периферии, а затем - в регистры другой периферии. И вторая запись - запускает взаимодействие 2-й периферии с первой, то между первой записью и 2-й записью необходимо вставить DMB. Иначе будет то работать, то глючить.
Если к примеру какая-то запись в регистр периферии включает её работу, и эта периферия сразу посылает запрос DMA-каналу. А до этого вы конфигурили данный DMA-канал, и в процессе конфигурирования очистили регистр DMA-запросов, то возможна ситуация, что конфигурация DMA-канала запишется в него после того, как включится периферия его использующая. И например запрос к DMA от периферии потеряется и она вечно будет ждать обслуживания со стороны DMA-канала.
DMB устраняет эту проблему.
Ну или другой вариант: Вы в регистре флагов запросов прерываний некоей периферии почистили флажки, потом почистили их в NVIC (перед тем как размаскировать), а потом размаскировали данное прерывание в NVIC. И оно тут же произошло (прерывание). Хотя ещё никакой активности с периферией не было. Просто Ваша команда очистки флажков дошла до периферии позже чем команда очистки флажков в NVIC. И NVIC успел опять защёлкнуть запрос прерывания.
haker_fox
QUOTE (jcxz @ Feb 14 2018, 00:07) *
Если Вы записали что-то в регистры некоей периферии, а затем - в регистры другой периферии.

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

Кстати, попробывал ожидать окончания транзакции по приёму - стало значительно лучше. Но вот с чистой передачей остаются проблемы. Приём мы не ведём. А как вы уже сказали, DMA при передаче лишь только отрапортует, что данные сброшены в регистры FIFIO, не более. Следовательно как гарантированно дождаться завершения именно передачи (без приёма) я пока не знаю. Прерывания от SSP соответствующих не нашёл(((
jcxz
Цитата(haker_fox @ Feb 14 2018, 06:41) *
Следовательно как гарантированно дождаться завершения именно передачи (без приёма) я пока не знаю. Прерывания от SSP соответствующих не нашёл(((

Никак. Всегда программировать RX-DMA-канал.
Не понимаю - а зачем Вы упорно пытаетесь обойтись без приёма? 1 DMA канал сэкономить? Так их там много вроде. Пропускную способность шины сэкономить? Так её ещё постараться надо чтобы загрузить.
И приоритет RX-DMA-канала всегда должен быть выше чем у TX-DMA.
haker_fox
QUOTE (jcxz @ Feb 14 2018, 23:14) *
Никак. Всегда программировать RX-DMA-канал.
Не понимаю - а зачем Вы упорно пытаетесь обойтись без приёма? 1 DMA канал сэкономить?

Нет. Сложновато получается. Допустим, мне надо только передать 10 кб по связанному списку. Значит приём "холостых" байт нужно вести в какой-то закольцованный связным списком буфер?! Вот мне это и кажется избыточным. Видимо придётся делать.
QUOTE (jcxz @ Feb 14 2018, 23:14) *
И приоритет RX-DMA-канала всегда должен быть выше чем у TX-DMA.

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

Стоп!!! Это что же такое я говорю, совсем заработался. Не надо на приём делать холостой связный списко. Можно просто не инкрементировать адрес приёмника в дма, и лишь хоть весь объём Вселенной в буфер из одного байта))))))
haker_fox
P.S.S.S.
И всё-таки особенность есть. Я доделал в драйвере SSP всё, о чём говорилось тут. Но в редких-редких случаях всё равно наблюдается то, что я написал в самом первом сообщении: в канале DMA, напроенным на приём, остаётся транзакция на 4 байта. В регистре "сырых" прерываний стоят флаги RORRIS и RTRIS. Т.е. буфер переполнен, и ещё таймаут. Но DMA даже не собирается забирать от туда ничего. При этом клок на шине, как я понимаю, даже уже и не нужен. Ведь данные в фифо. Что интересно, если программно сформировать burst запрос, то флаги очищаются, а DMA рапортует об успешном завершении транзакции. Правда валидность данных я не проверял в таком режиме, думаю, что они не будут правильным, т.к. установлен "оверран". Вроде как проблему решило изменение burst rx на 1 байт вместо 4х. В документации не нашёл прямого ответа на свой вопрос: какие линии запроса заведены на DMA от SSP (burst, single или оба). Возможно невнимательно читал.
jcxz
Цитата(haker_fox @ Feb 15 2018, 02:13) *
Стоп!!! Это что же такое я говорю, совсем заработался. Не надо на приём делать холостой связный списко. Можно просто не инкрементировать адрес приёмника в дма, и лишь хоть весь объём Вселенной в буфер из одного байта))))))

Вот именно.

Цитата(haker_fox @ Feb 15 2018, 10:27) *
Вроде как проблему решило изменение burst rx на 1 байт вместо 4х. В документации не нашёл прямого ответа на свой вопрос: какие линии запроса заведены на DMA от SSP (burst, single или оба). Возможно невнимательно читал.

Я уже несколько лет не работал с LPC17xx. Поднял свои старые исходники, посмотрел: у меня драйвер SSP для LPC1768 не использует burst, а для LPC1778 - использует. Код драйвера - один и тот же. Уже не помню с чем это связано, видимо тоже были какие-то проблемы. Драйвер этот я хорошо испытывал - интенсивный многозадачный псевдослучайный обмен с флешкой на SCLK==25...30МГц параллельно с таким же обменом с FRAM и другими DMA-транзакциями. Работает уже много лет в десятках тысяч выпущенных устройств у заказчиков. Без проблем.
Нажмите для просмотра прикрепленного файла
Для LPC1778:
#define BURST_MODE 1
Для LPC1768:
#define BURST_MODE 0
ActDF()/ActFram() - собственно старт транзакции с программированием DMA.
isrDMA_dflash()/isrDMA_fram() - должны вызываться из общего ISR для GPDMA.
До любой транзакции вызывается инит: InitDFlashFram() (до старта ОС), а затем - ConfigureDFlashFram() (после старта ОС).
haker_fox
QUOTE (jcxz @ Feb 15 2018, 17:00) *
Драйвер этот я хорошо испытывал

Спасибо, что выложили его сюда! Для меня это будет прекрасным примеров, ведь интересно посмотреть драйвер реально работающий, реально испытанный!!!

А так с burst rx = 1 уже с обеда без сбоев всё работает))) Я написал на форуме nxp вопрос, но там подобные без ответа лежат по нескольку месяцев)))
jcxz
Цитата(haker_fox @ Feb 15 2018, 11:14) *
Спасибо, что выложили его сюда!

Пожалуйста. Пользуйтесь. rolleyes.gif

Цитата(haker_fox @ Feb 15 2018, 11:14) *
А так с burst rx = 1 уже с обеда без сбоев всё работает))) Я написал на форуме nxp вопрос, но там подобные без ответа лежат по нескольку месяцев)))

Возможно и мой будет работать - я его на LPC43xx не использовал, так как на LPC43xx флешку я подключал на SPIFI.
Файл fram_flash.h который в архиве - для устройства на LPC1778, для LPC1768 - он немного другой, но отличия там - в указанном дефайне, частоте SCLK, списке поддерживаемых чипов и ещё какой-то мелочи.
haker_fox
QUOTE (jcxz @ Feb 15 2018, 17:20) *
Возможно и мой будет работать - я его на LPC43xx не использовал, так как на LPC43xx флешку я подключал на SPIFI.

В нашем случае получилось лёгкое извращение, т.к. на одной SSP висит несколько устройств от слишком медленных сигма-дельта АЦП до одной N25Q128. В этом микроконтроллере есть ещё одна SSP, но она занята действительно под высокоскоростной обмен, и её трогать нельзя. А вот SSP0 пришлось через программный мультиплексор (набор виртуальных шин) поключить к нескольким дейвасам, а ОС в каждом потоке работает со своим устройством. Правда общая запись/чтение на флешку не превышает 45 кБ/сек. Возможно можно оптимизировать, но пока оставил так. Аппаратный SPIFI использовать не вышло по техническим причинам.
jcxz
Цитата(haker_fox @ Feb 15 2018, 12:06) *
В нашем случае получилось лёгкое извращение, т.к. на одной SSP висит несколько устройств от слишком медленных сигма-дельта АЦП до одной N25Q128.

У меня указанный драйвер на каких-то устройствах работает с чипами FLASH и FRAM сидящими на одном SSP, на других - на разных SSP.
Для этого там и используются семафоры ОС.
haker_fox
QUOTE (jcxz @ Feb 15 2018, 18:57) *
Для этого там и используются семафоры ОС.

Да, я заметил) А какие у вас скорости доступа к флеш, не помните на вскидку?))
jcxz
Цитата(haker_fox @ Feb 15 2018, 15:07) *
Да, я заметил) А какие у вас скорости доступа к флеш, не помните на вскидку?))

SCLK? В хидере указана. Для LPC1778 == 30МГц.
haker_fox
QUOTE (jcxz @ Feb 15 2018, 21:16) *
SCLK? В хидере указана. Для LPC1778 == 30МГц.

Нет, я имел в виду скорость записи и чтения на флешку. Ну например, запись 1 Мб/сек, чтение 10 Мбайт/сек.
jcxz
Цитата(haker_fox @ Feb 16 2018, 02:14) *
Нет, я имел в виду скорость записи и чтения на флешку. Ну например, запись 1 Мб/сек, чтение 10 Мбайт/сек.

Те устройства, где тот мой драйвер используются, не нуждаются в реал-тайм записи потоков.
Там, где нужна была запись реал-тайм-потоков, я строил драйвер по-другому - с гарантированным временем доступа службе, требующей реал-тайм-записи.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.