реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Неверные данные при чтении по SPI через DMA
avg33
сообщение Aug 7 2018, 17:53
Сообщение #1





Группа: Участник
Сообщений: 12
Регистрация: 7-08-18
Пользователь №: 106 564



Всем привет. Пытаюсь прочитать SPI флэшку по DMA. Работаю через USART.
Суть дела в следующем. Допустим, буду читать из флэш по 100 байт. Для этого надо отправить на флэш 105 байт: 5 байт команды и 100 байт фиктивной записи.
Сначала я повесил прием на 2 канал DMA, а запись во флэш реализовал прямо в цикле for:

Код
uint8_t tx_buf[105]; //отсюда пишем во флэш, первые 5 байт - команда
uint8_t rx_buf[105]; //сюда DMA положит прочитанное

void read()
{
    //настройка DMA на прием по 2 каналу
    //по окончании приема 105 байт сработает прерывание IRQ_RX()
    init_DMA_RX();
    UART2_SSR2_RIE = 1; //разрешить прерывание по чтению
    
    //запись 105 байт
    FLASH_CS = FLASH_ON; //установить CS
    for(uint16_t i=0; i<105; ++i)
    {
        while (UART2_SSR2_TDRE == 0); //жду освобождения регистра передачи
        TRD2 = tx_buf[i]; //отправляю байт на флэш
    }
    FLASH_CS = FLASH_OFF; //снять CS
}

void IRQ_RX()
{
    //сюда придем по завершению приема
    //здесь выполняем всякие служебные вещи, чистим флаги и тд
    //и повторное чтение в заисивмости от условия
    if(/*условие*/)
        read();
}


Такой сценарий нормально работает. И при одиночном и при повторном вызове read() в rx_buf лежат валидные данные: 5 байт 0xFF и 100 байт из флэш
Но писать через for долго. Поэтому передачу tx_buf я тоже повесил на канал DMA:
Код
void read()
{
    //настройка DMA на прием по 2 каналу
    //по окончании приема 105 байт сработает прерывание IRQ_RX()
    init_DMA_RX();
    UART2_SSR2_RIE = 1; //разрешить прерыване по чтению
    
    //настройка DMA на передачу по 3 каналу
    //по окончании передачи 105 байт сработает прерывание IRQ_TX()
    init_DMA_TX();
    UART2_SSR2_TIE = 1; //разрешить прерывание по чтению
    
    FLASH_CS = FLASH_ON; //установить CS
}

void IRQ_TX()
{
    //сюда придем по завершению приема
    //здесь выполняем всякие служебные вещи, чистим флаги и тд
    //и снимаем CS
    FLASH_CS = FLASH_OFF;
}

void IRQ_RX()
{
/*...*/
    if(/*условие*/)
        read();
}


И вот этот сценарий дает сбой. Проблема в том, что в какой-то момент устанавливается в 1 флаг переполнения ORE USART`а.
Соответственно, в rx_buf по окончанию приема лежат невалидные данные. Обычно в конце буфера какая-то чушь, иногда в начале или вообще весь буфер бред.
Бывает и такое, что первый вызов read() дает корректные данные, но второй всегда невалидные.
Момент выставления ORE в единицу уловить невозможно, я так и не выявил зависимости. Что я делаю не так, в чем может быть проблема?
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Aug 7 2018, 18:52
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



Цитата(avg33 @ Aug 7 2018, 20:53) *
Всем привет. Пытаюсь прочитать SPI флэшку по DMA. Работаю через USART.

Что за контроллер-то?
Не забывайте, что контроллер DMA выставит флаг "транзакция завершена" после перекладывания последней порции данный лишь в сдвиговый регистр. Поэтому
Код
void IRQ_TX()
{
    //сюда придем по завершению приема
    //здесь выполняем всякие служебные вещи, чистим флаги и тд
    //и снимаем CS
    FLASH_CS = FLASH_OFF;
}

не придете Вы сюда по завершению приема. Вы должны в прерывании этом выставить флажок (либо настроить прерывание по Transfer Complete), чтобы сигнализировать о реальном завершении транзакции. Иначе снимите CS до истинной передачи последнего слова.
Либо Вы не правильно настроили связку сигналов DMA-контроллера с модулем USART по передаче.

Сообщение отредактировал Arlleex - Aug 7 2018, 18:54
Go to the top of the page
 
+Quote Post
avg33
сообщение Aug 7 2018, 19:08
Сообщение #3





Группа: Участник
Сообщений: 12
Регистрация: 7-08-18
Пользователь №: 106 564



Arlleex, благодарю за оперативный ответ.

Цитата("Arlleex")
Что за контроллер-то?

F2MC-16FX MB96600 Series

Цитата("Arlleex")
Иначе снимите CS до в процессе передачи последнего слова.

И вправду. А если снять его в IRQ_RX() ? По идее прерывание по приему должно сработать после того, как DMA переложит последний байт в буфер. Или там тоже нюансы со сдвиговым регистром?

Цитата("Arlleex")
Либо Вы не правильно настроили связку сигналов DMA-контроллера с модулем USART по передаче.

По передаче или приему? Или и то и другое?) Я просто указал DMA сколько и откуда писать, куда читать, по каким перываниям срабатывать. Даже не знаю, где там можно ошибиться
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Aug 7 2018, 19:26
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



Цитата(avg33 @ Aug 7 2018, 22:08) *
F2MC-16FX MB96600 Series

Не работал, но логика периферийных узлов во всех МК, в общем-то не глобально отличается...

Цитата(avg33 @ Aug 7 2018, 22:08) *
И вправду. А если снять его в IRQ_RX()?

Уже теплее. Так и нужно, да.

Цитата(avg33 @ Aug 7 2018, 22:08) *
По передаче или приему? Или и то и другое?) Я просто указал DMA сколько и откуда писать, куда читать, по каким перываниям срабатывать. Даже не знаю, где там можно ошибиться

Ну если прием у Вас работает при передаче "ручками", то, очевидно, исходя от противного - проблема в передаче laughing.gif Хотя не ручаюсь точно - ORE это же флаг переполнения входного буфера (то есть туда пришли данные когда еще предыдущие не считали). Поэкспериментируйте, решение где-то рядом.
Go to the top of the page
 
+Quote Post
avg33
сообщение Aug 7 2018, 20:11
Сообщение #5





Группа: Участник
Сообщений: 12
Регистрация: 7-08-18
Пользователь №: 106 564



Цитата("Arlleex")
Хотя не ручаюсь точно - ORE это же флаг переполнения входного буфера (то есть туда пришли данные когда еще предыдущие не считали).

Заметил, что если поставить точку останова в IRQ_TX(), то на этот момент ORE уже стоит. И если DMA что-то не успел дописать в буфер, то с этого байта в буфере будет мусор из повторяющегося значения входного регистра. А еще бывает мусор в начале буфера и его на ORE никак не списать, ибо дальше идут данные валидные. Черт знает вообще откуда это все берется
Go to the top of the page
 
+Quote Post
avg33
сообщение Aug 9 2018, 16:55
Сообщение #6





Группа: Участник
Сообщений: 12
Регистрация: 7-08-18
Пользователь №: 106 564



1. По совету Arlleex переместил снятие CS из прерывания по передаче IRQ_TX() в прерывание по чтению IRQ_RX()
2. Обнаружено, что с флешки на ножку контроллера RX приходит 3.3V, а контроллер работает с 5V. На всякий случай на вывод флешки был вкорячен подтягивающий резистор

После этого стало намного лучше. Но на скоростях >12000 бод время от времени в буфере продолжали появляться невалидные данные.
При этом у проблемы появилась системность: на очередном чтении буфер сначала целиком заполнялся 0xFF (это уровень на линии по умолчанию), а следующая итерация чтения давала либо то же самое, либо читала что-то похожее на правду, но гарантированно устанавливала ORE.
Порывшись в отладчике стало ясно, что к данному глюку приводит ситуация, когда прерывание по чтению IRQ_RX() вызывается раньше, чем прерывание по передаче IRQ_TX(). В IRQ_TX() у меня только снятие флага прерывания по передаче и отключение канала DMA. Не совсем понимаю, как это может вызвать забиваение буфера в 0xFF после очередного вызова read(), но четкая связь на лицо.

В общем, мне нужно сделать так, чтобы IRQ_TX() гарантированно вызывался раньше, чем IRQ_RX(). Я попробовал назначить IRQ_TX() более низкий приоритет и, кажется, это работает.
Насколько надежен и адекватен такой метод или лучше разрешить данную ситуацию как-то иначе через извращения в коде?
Go to the top of the page
 
+Quote Post
Arlleex
сообщение Aug 10 2018, 06:49
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264



Цитата(avg33 @ Aug 9 2018, 19:55) *
Насколько надежен и адекватен такой метод или лучше разрешить данную ситуацию как-то иначе через извращения в коде?

Все-таки для начала желательно посмотреть логическим анализатором на лапки этого чудного SPI.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 15th June 2025 - 04:40
Рейтинг@Mail.ru


Страница сгенерированна за 0.01427 секунд с 7
ELECTRONIX ©2004-2016