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

Здравствуйте. Пишу код для приема данных по SPI (используется для связи с SD-картой). Что-то пока не работет.

 

uint8_t SPI_Recv(uint8_t *buff, uint32_t size)
{
     *pDMA5_PERIPHERAL_MAP      = 0x5000;     
     *pSPI_CTL &= ~SPE;
     
     *pDMA5_CONFIG = WDSIZE_8 | WNR;
     *pDMA5_START_ADDR = (void *)buff;
     *pDMA5_X_COUNT = size;
     *pDMA5_X_MODIFY = 1;
     
     *pDMA5_CONFIG = (*pDMA5_CONFIG | DMAEN);
     
     *pSPI_FLG = FLS;
     *pSPI_BAUD = 4;
     *pSPI_CTL = 0x2 | MSTR;
     *pSPI_CTL |= SPE;
     
     // wait until dma transfers for spi are finished      
     sleep(50);
     
     *pDMA5_CONFIG = (*pDMA5_CONFIG & ~DMAEN);
     
     *pSPI_CTL &= ~SPE;
     
     return size;
}

 

Проблема в том, что не принимается первый байт в посылке. В чем ошибка в моем коде?

 

Если все это хазяйство заменить на

uint8_t SPI_Recv(uint8_t *buff, uint32_t size)
{
    uint32_t i;
    for(i = 0; i < size; i++)
        buff[i] = SPI_SendByte(0xFF);
    return size;
}

uint8_t SPI_SendByte(uint8_t outgoing)
{
    uint8_t incoming = 0;    
    while(!(*pSPI_STAT & SPIF));
    *pSPI_TDBR = outgoing;
    while(*pSPI_STAT & RXS)
    incoming = *pSPI_RDBR;
    return(incoming);    
}

то все отлично работает, далее подымается драйвер FAT32. Но вот только когда заменяю функцию на использование DMA сразу глюки, теряется 1 байт.

В чем ошибка? Кто-то может поделится рабочим куском кода для приема по SPI с использованием DMA?

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


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

По идее, (в даташите написано) первый байт не должен использоваться как информационный.

Попробуйте почистить FIFO перед принятием блока и затем установить флаг - "буфер полный".

 

И зачем Вы 2 раза обращатесь к *pSPI_CTL ?

Настройка и запуск - всё делается в одной команде.

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


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

По идее, (в даташите написано) первый байт не должен использоваться как информационный.

А как его использовать не как информационный, если SD-карта возвращает ответ уже на первый байт (если заменить DMA на не DMA, функции я указал, все работает)???

Попробуйте почистить FIFO перед принятием блока
Это сделал не помогло.

и затем установить флаг - "буфер полный".
Не понял, не подскажите как это сделать?

 

И зачем Вы 2 раза обращатесь к *pSPI_CTL ?

Настройка и запуск - всё делается в одной команде.

Это тоже исправил.

Пока после предложенных изменений не заработало. При чем функция отправки с использованием DMA работает правильно. Т.е. если отправку делать по DMA, а когда нужен прием не использовать DMA, то все работает.

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


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

1. В случае с аппаратными устройствами, Вы абсолютно правы.

Пропускать первый байт нельзя.

 

2. установка флага:

*pSPI_CTL = SZ; //Stop SPI

*pSPI_TDBR = 0; //Set Buffer full

 

Смысл, чтоб при поступлении нового символа в полный буфер, контроллер DMA сделал транзакцию в память.

И ещё, есть смысл убрать флаг WDSIZE_8, он всё равно = 0.

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


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

*pSPI_CTL = SZ; //Stop SPI

Что-то я торможу, судя с документации SZ означает когда SPI_TDBR пуст, производится отправка нуля, а если не установлен то передача последнего слова. Поэтому что-то не понял.

При общении с SD-картой, процессор является мастером, и при приема данных я долже отправлять код 0xFF иначе SD-карта это примет за ошибку. Поэтому установка этого флага приведек к неработоспособности работы функций даже без DMA.

 

*pSPI_TDBR = 0; //Set Buffer full

А эта запись, яя не понимаю что она очищает. Записывая сюда ноль, мы подразумеваем что следующая отправка (в интерфейсе SPI для того что бы что-то принять нужно отправить, для мастера) будет содержать байт ноль, что для нас тоже критично, если процессор принимает данные с SD-карту он должен отправлять 0xFF.

 

Ещё будут какие-то предположения? Наверняка же кто-то уже реализовывал отправку/прием данных по SPI с использованием DMA, да и очень возможно что даже для связки с SD-картой. Так если не жалко не поделитесь кодом, именно двуня функциями, иннициализацией и приемо/отправкой???

 

Заранее благодарен.

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


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

Тогда под Ваш случай в SPI_TDBR нужного вписать 0xFF, когда Вы принимаете по DMA этот код и будет передаваться карте.

 

Я просто не сталкивался вплотную с SD протоколом, а использовал SPI DMA под свой.

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


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

Тогда под Ваш случай в SPI_TDBR нужного вписать 0xFF, когда Вы принимаете по DMA этот код и будет передаваться карте.
Я попробывал использовать, но все равно 1 байт теряется :(

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


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

А в смысле байт "теряется"?

Его просто нет или там какой-то случайный мусор от предидущего пакета?

Или константное значение?

 

Что в знакоместе по адресу DMA_Buff[0]?

Куда попадает байт номер 2?

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

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


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

А в смысле байт "теряется"?

Его просто нет или там какой-то случайный мусор от предидущего пакета?

Или константное значение?

 

Что в знакоместе по адресу DMA_Buff[0]?

Куда попадает байт номер 2?

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

Ну к примеру должно быть "0x00, 0x00, 0x01, 0xAA", а получаю я "0х00, 0х01, 0хAA, 0xFF".

Или нужно "0x80, 0xFF. 0x80, 0x00" а я получаю "0xFF, 0x80, 0x00, 0xFF"

перед считыванием в буфер заносил мусор что определить что данные реально записываются а не остаются. Как видно данные сдвигаются влево, а последний байт FF.

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


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

Хм... завтра на работе потестю у себя на плате.

А пока, предложение одно, заголовок протокола обслуживать по прерываниям, а тело страницы памяти пересылать по ДМА.

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


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

А пока, предложение одно, заголовок протокола обслуживать по прерываниям, а тело страницы памяти пересылать по ДМА.
А вы бы не могли по подробнее, что именно по прерываниям а что с DMA я не понял.

Главное функция отправки

uint8_t SPI_Send(const uint8_t *buff, uint32_t size)
{
     *pDMA5_PERIPHERAL_MAP      = 0x5000;
     while(!(*pSPI_STAT & SPIF));         
     *pSPI_CTL = 0;

     
     *pDMA5_CONFIG = WDSIZE_8 | RESTART;
     *pDMA5_START_ADDR = (void *)buff;
     *pDMA5_X_COUNT = size;
     *pDMA5_X_MODIFY = 1;
     
     *pDMA5_CONFIG = (*pDMA5_CONFIG | DMAEN);

     *pSPI_FLG = FLS;
      *pSPI_BAUD = 4;
     *pSPI_CTL = 0x3 | MSTR  | SPE;
     
     while (*pDMA5_IRQ_STATUS & DMA_RUN); // wait for DMA to complete
   
Check_TXS:
     while (*pSPI_STAT & TXS);
   
     if (*pSPI_STAT & TXS)
        goto Check_TXS;
       
     while (!(*pSPI_STAT & SPIF));     

     *pDMA5_CONFIG = (*pDMA5_CONFIG & ~DMAEN);
     
     SPI_HardwareInitial(4);
     
     return size;
}

А вот принимать я принимаю вот так:

uint8_t SPI_Recv(uint8_t *buff, uint32_t size)
{
    uint32_t i;
    for(i = 0; i < size; i++)
        buff[i] = SPI_SendByte(0xFF);
    return size;
}

uint8_t SPI_SendByte(uint8_t outgoing)
{
    uint8_t incoming = 0;    
    while(!(*pSPI_STAT & SPIF));
    *pSPI_TDBR = outgoing;
    while(*pSPI_STAT & RXS)
    incoming = *pSPI_RDBR;
    return(incoming);    
}

 

Кстати когда нужно отправить один байт я тоже использую SPI_SendByte. В вот такой связке все работает, поднялась библиотека FAT32 от чана.

 

Как только заменяю на прием с помощью DMA сразу глюки, последняя версия этой функции такая.

uint8_t SPI_Recv(uint8_t *buff, uint32_t size)
{
     *pDMA5_PERIPHERAL_MAP      = 0x5000;
     while(!(*pSPI_STAT & SPIF));  
     *pSPI_CTL = 0;
     sleep(10);
    
     
     *pDMA5_CONFIG = WDSIZE_8 | WNR | RESTART;
     *pDMA5_START_ADDR = (void *)buff;
     *pDMA5_X_COUNT = size;
     *pDMA5_X_MODIFY = 1;
     
     *pDMA5_CONFIG = (*pDMA5_CONFIG | DMAEN);
     
     *pSPI_FLG = 0xEF | FLS;
     *pSPI_BAUD = 4;
     
      *pSPI_TDBR = 0xFF;     
      *pSPI_CTL = 0x2 | MSTR | EMISO | GM | SPE;         
     
     // wait until dma transfers for spi are finished
     sleep(50);
     
     // turn off DMA
     *pDMA5_CONFIG = (*pDMA5_CONFIG & ~DMAEN);
     
     SPI_HardwareInitial(4);
     
     return size;
}

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


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

Чтоб поподробнее, мне нужно хотя-бы прочитать как SD карта работает.

На моей плате только межпроцессорный обмен и чтение флешек.

 

Можно еще попробовать сконфигурить 2х байтный ДМА трансфер, тк SPI регистр 2х байтный.

Вероятно самый первый байт и портится, такая есть идея.

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


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

HOUSEHOUSE, а Вы обратили внимание на последнее предложение из описания работы DMA на прием из SPI? Очень похоже, что сдвиг у Вас получается именно оттуда.

In Receive mode, as long as there is data in the SPI DMA FIFO

(the FIFO is not empty), the SPI continues to request a DMA

write to memory. The DMA engine continues to read a word from

the SPI DMA FIFO and writes to memory until the SPI DMA

Word Count register transitions from 1 to 0. The SPI continues

receiving words until SPI DMA mode is disabled.

ИМХО, ограниченность блекфиновского DMA в связке с SPI делает его малопригодным для протоколов сложнее 25xx флешки :(

Конечно, сочетая работу поллингом и пересылки блоков можно работать и с SD, но принимать придется в обязательном порядке блок данных и CRC одновременно, что не всегда удобно.

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


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

Вопрос для тех кто юзал BF542. Как там дело обстоит с аппаратной поддержкой SD?

У меня приложение занимается либо сжатием видео потока либо аудио потока, потом это все мне нужно куда-то сохранить. Поэтому меня не устраивает ограниченность DMA и использование поллинга. Вопрос в том что смогу ли я на BF542 добится того что к примеру я послал через DMA 512 байт для записи на SD и забыл о них, потом в прерывании я просто проанализировал и возможно далее начал записывать. Т.е. мне нужно что бы процессор на носители тратил ограниченное время. С BF542 этого добиться можно?

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


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

Прочитал даташит на BF542 и примеры стандартные в VisualDSP, предполагаю что там с SD вообще проблем не должно быть.

 

У меня вопрос по поводу BF533 в общем я добился скорости 450-500 килобайт в секунду (я про SD). Но это не скорость записи на прямую в SD, а именно в файл, если писать без файловой системы то скорость чуточку быстрее.

Запись я осуществляю с нулевого адресса (т.е. это первый банк SDRAM). Я подумал что такая низкая скорость может быть из-за медленного доступа к SDRAM и попытался подключить cache. Но после его подключение скорость практически не изменилась. У меня вопрос, все так и должно было быть? Или я кэш как-то не правильно подключаю?

Я испробывал все виды кэшей, подключал как просто функции, так и создавал проект в котором все формируется напрямую перед main.

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


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

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

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

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

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

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

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

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

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

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