Периферийное устройство SPI моего AT91SAM7X512 отключается на время X (изменяется X), которое я записываю в SPI_TDR
.
В результате процессор зависает в цикле while, который проверяет флаг TDRE
в SPI_SR
. Этот цикл while находится в функции SPI_Write()
, которая принадлежит программному пакету / библиотеке, предоставляемой ATMEL.
Проблема возникает произвольно - иногда все работает нормально, а иногда не удается при повторных попытках (попытка = загрузка того же двоичного файла в MCU и запуск программы).
Конфигурации (определены в порядке записи):
SPI_MR
:
MSTR
= 1
PS
= 0
PCSDEC
= 0
PCS
= 0111
DLYBCS
= 0
SPI_CSR[3]
:
CPOL
= 0
NCPHA
= 1
CSAAT
= 0
BITS
= 0000
SCBR
= 20
DLYBS
= 0
DLYBCT
= 0
SPI_CR
:
После установки конфигураций код проверяет, включен ли 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.
}
Вопросы:
- Что приводит к отключению периферийного устройства SPI при записи в
SPI_TDR
?
Должен ли я откомментировать строку в 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);
}
Что-то не так с кодом выше, который передает 5 байтов данных?
Обратите внимание:
- Номер строки NPCS. 3 является линией GPIO (значит, в режиме PIO) и не контролируется контроллером SPI.
Я сам контролирую эту строку в коде, удаляя / утверждая вывод ChipSelect # 3 (NPCS3), когда это необходимо.
Причина, по которой я это делаю, заключается в том, что возникли проблемы при попытке позволить контроллеру SPI контролировать этот вывод.
- Я не использовал контроллер PDC / DMA и предпочитаю не использовать его.
Я не перезагружал периферийное устройство SPI дважды, потому что из-за ошибок сообщалось, что он должен сбрасываться дважды только в том случае, если я выполняю сброс, чего я не делаю. Цитируя опечатки:
Если выполняется программный сброс (SWRST в регистре управления SPI), SPI может не работать
правильно (часы включаются до выбора чипа.)
Устранение проблемы / Обходной путь
Поле SPI Control Register, SWRST (сброс программного обеспечения) необходимо записать дважды, чтобы
установлен прямо.
Я заметил, что иногда , если я помещаю задержку перед записью в регистр SPI_TDR
(в SPI_Write()
), то код работает отлично, и обмен данными успешен. *
Полезные ссылки:
Пример инициализации SPI и выполнения передачи 5 байтов высоко ценится и полезен.