Периферийное устройство SPI AT91SAM7X512 отключается при записи в SPI_TDR - PullRequest
2 голосов
/ 18 марта 2010

Периферийное устройство SPI моего AT91SAM7X512 отключается на время X (изменяется X), которое я записываю в SPI_TDR. В результате процессор зависает в цикле while, который проверяет флаг TDRE в SPI_SR. Этот цикл while находится в функции SPI_Write(), которая принадлежит программному пакету / библиотеке, предоставляемой ATMEL. Проблема возникает произвольно - иногда все работает нормально, а иногда не удается при повторных попытках (попытка = загрузка того же двоичного файла в MCU и запуск программы).

Конфигурации (определены в порядке записи):

  1. SPI_MR:
    • MSTR = 1
    • PS = 0
    • PCSDEC = 0
    • PCS = 0111
    • DLYBCS = 0
  2. SPI_CSR[3]:
    • CPOL = 0
    • NCPHA = 1
    • CSAAT = 0
    • BITS = 0000
    • SCBR = 20
    • DLYBS = 0
    • DLYBCT = 0
  3. SPI_CR:
    • SPIEN = 1

После установки конфигураций код проверяет, включен ли SPI, проверяя флаг SPIENS.

Я выполняю передачу байтов следующим образом:

const short int dataSize = 5;
// Filling array with random data
unsigned char data[dataSize] = {0xA5, 0x34, 0x12, 0x00, 0xFF};
short int i = 0;
volatile unsigned short dummyRead;

SetCS3();   // NPCS3 == PIOA15
while(i-- < dataSize) {
    mySPI_Write(data[i]);
    while((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
    dummyRead = SPI_Read(); // SPI_Read() from Atmel's library
}
ClearCS3();
/**********************************/
void mySPI_Write(unsigned char data) {
    while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
    AT91C_BASE_SPI0->SPI_TDR = data;
    while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TDRE) == 0); // <-- This is where
    // the processor hangs, because that the SPI peripheral is disabled
    // (SPIENS equals 0), which makes TDRE equal to 0 forever.
}

Вопросы:

  1. Что приводит к отключению периферийного устройства SPI при записи в SPI_TDR?
  2. Должен ли я откомментировать строку в SPI_Write(), которая читает регистр SPI_RDR?
    Значит, 4-я строка в следующем коде: (4-я строка изначально помечена как комментарий)

    void SPI_Write(AT91S_SPI *spi, unsigned int npcs, unsigned short data)
    {
        // Discard contents of RDR register
        //volatile unsigned int discard = spi->SPI_RDR;
        /* Send data */
        while ((spi->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
        spi->SPI_TDR = data | SPI_PCS(npcs);
        while ((spi->SPI_SR & AT91C_SPI_TDRE) == 0);
    }
    
  3. Что-то не так с кодом выше, который передает 5 байтов данных?

Обратите внимание:

  • Номер строки NPCS. 3 является линией GPIO (значит, в режиме PIO) и не контролируется контроллером SPI. Я сам контролирую эту строку в коде, удаляя / утверждая вывод ChipSelect # 3 (NPCS3), когда это необходимо. Причина, по которой я это делаю, заключается в том, что возникли проблемы при попытке позволить контроллеру SPI контролировать этот вывод.
  • Я не использовал контроллер PDC / DMA и предпочитаю не использовать его.
  • Я не перезагружал периферийное устройство SPI дважды, потому что из-за ошибок сообщалось, что он должен сбрасываться дважды только в том случае, если я выполняю сброс, чего я не делаю. Цитируя опечатки:

    Если выполняется программный сброс (SWRST в регистре управления SPI), SPI может не работать правильно (часы включаются до выбора чипа.)
    Устранение проблемы / Обходной путь
    Поле SPI Control Register, SWRST (сброс программного обеспечения) необходимо записать дважды, чтобы установлен прямо.

  • Я заметил, что иногда , если я помещаю задержку перед записью в регистр SPI_TDRSPI_Write()), то код работает отлично, и обмен данными успешен. *

Полезные ссылки:

Пример инициализации SPI и выполнения передачи 5 байтов высоко ценится и полезен.

1 Ответ

1 голос
/ 15 мая 2013

Вы используете

while(i-- < dataSize)

уменьшает целое число со знаком i, не увеличивает его и получает доступ к data[i] до тех пор, пока i не переполнится до положительного значения. Кто знает, что происходит, к какой памяти или регистрам вы обращаетесь? Использование целых чисел без знака обычно лучше, если вам не нужно хранить отрицательные значения.

Кроме того, вы уже проверяете на TXEMPTY, что означает, что данные перемещаются в сдвиговый регистр И отправляются. Таким образом, вам также не нужно проверять TDRE, что означает, что данные перемещаются в регистр сдвига, но не могут быть отправлены.

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

...