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

 
 
> Неверные данные при чтении по 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



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

 


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


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