Полная версия этой страницы:
Отправляю пакет пр SPI
не могу понять,отправляю пакет через SPI, теряются биты.
AT91PS_SPI pSpi = AT91C_BASE_SPI;
AT91PS_AIC pAic = AT91C_BASE_AIC;
unsigned int temp;
unsigned int spib;
temp = pAic->AIC_IMR;
while(pSpi->SPI_SR & AT91C_SPI_TDRE==0);
pSpi->SPI_TDR = (data & 0xFFFF) | (CS << 16);
while(pSpi->SPI_SR & AT91C_SPI_RDRF==0);
pAic->AIC_IECR = temp;
spib=((pSpi->SPI_RDR) & 0xFFFF);
return spib;
GetSmart
May 9 2006, 16:22
Цитата(glebka @ May 9 2006, 19:14)

не могу понять,отправляю пакет через SPI, теряются биты.
Если у вас теряются именно биты, а не байты, например первые или последние несколько бит, то возможно это из-за того, что два устройства (процессор и что-то внешнее) настроены неправильно по отношению друг к другу. Обычно есть 4 режима SPI плюс ещё порядок следования бит. И не все из них совместимы друг с другом. Из сообщения много непонятно о проблеме. Неясно что стоит снаружи проца (на шине SPI) и неясно как настроен SPI. Ещё может быть проблема в очень длинных проводах между устройствами (от полуметра и более), но это тоже связано с высокой скоростью обмена.
Edmundo
May 9 2006, 16:55
Насколько я понял, SPI замкнут сам на себя.
У меня тоже есть подобная проблема, но я пока грешу на передатчик. В чем дело у меня, отпределю уже только на работе (дома ни осциллоскопа, ни даже мультиметра). Но симптомы похожие: при приеме пропадает первый бит данных (MSB), количество бит и их положение в байте корректные (пробовал и опрос в цикле, и по DMA).
Все-таки поддерживаю GetSmart, конкретизируйте немного, как настроен SPI, как подключен.
GetSmart
May 9 2006, 17:46
Насколько я знаю, передавать на себя и в большинство внешних устройств можно только в режимах 0 и 3. Другие режимы очень специфичные и мало для чего пригождаются. То есть в режимах 1 и 2 так и должно быть пропадение одного бита. Это нормально. Режим 0 => CPHA = CPOL = 0, режим 3 => CPHA = CPOL = 1.
Ещё меня удивило, что в одной процедуре анализируются два флага готовности. Я так никогда не делаю. Достаточно проверки одного флага.
Прошу прощения. за неправильно сформулированый вопрос. отправляю пакет из 48 битов(команду)в сторону sd карты.во время передачи видно как на осциллографе первый бит команды сдвигается на 1 байт по отношению к началу clk и плюс при по байтной отправке между отправленными байтами паузы во время которых проподает chip select . я грешу на неправильную установку spi.хотя пользуюсь примером кода взятого с форума и сайта Lamerka и работающего в другом устройстве.
может кто-нибудь подскажет. или где посмотреть пример кода. пример с olimex есть ,разобрал попробовал теже грабли.
GetSmart
May 9 2006, 18:32
Даю вырезки для работы с SPI LPC213x. Подойдёт и ко многим другим. С AT91 не знаком, так что немного переделаете. Вообще, процедуры написаны так, чтобы максимально использовать скорость процессора. То есть во время передачи байта можно выполнять другие действия.
Процедуры инициализации:
#define PCLKFREQ 14745600*4
void LPC213xInitSPI0Master()
{
PINSEL0 = (PINSEL0 & ~0xff00) | 0x1500; // for SCK0, MISO, MOSI, SSEL-
SPCCR0 = PCLKFREQ / 921600; // скорость = 0.6912 MHz (~80 КБ/сек)
SPCR0 = 0x20;
if (SPSR0) {}; // просто чтение для сброса флага SPIF
SPDR0 = '!'; // это чтобы изначально бит SPIF (TDRE) установился
}
void txByteSPI0(long byte)
{
if (SPSR0) {} // просто чтение для сброса флага SPIF
SPDR0 = byte;
}
long rxtxByteSPI0(long byte)
{
for(uInt i=0; i<0x10000; i++) // 1/50 sec - это на всякий случай. Всё бывает на свете!
if (SPSR0_bit.SPIF) // это бит завершения передачи байта в мастере (и приёма в слэйве)
{
long j = SPDR0;
if (byte >= 0) SPDR0 = byte;
return(j);
}
LPC213xInitSPI0Master();
return(0);
}
Рабочие процедуры:
void READ_ADS1218(uInt cmd, uInt cnt, uByte *ptr)
{
_ON_CS_ADS1218;
txByteSPI(cmd);
rxtxByteSPI(cnt-1);
_WAIT(_50Tosc);
rxtxByteSPI(0);
while (cnt--)
if (cnt) *ptr++ = rxtxByteSPI(0);
else *ptr = rxtxByteSPI(-1); // завершение передачи
_OFF_CS_ADS1218;
}
Пояснение:
В моей схеме был режим мастер, а вывод SSEL вообще не использовался. Сначала вручную сбрасывается сигнал ~CS на нужное внешнее устройство. Затем вызывается процедура передачи первого байта без анализа флагов (txByteSPI0(long byte)). После сколько угодно раз процедуру уже анализирующую флаги (rxtxByteSPI0(long byte)). Однако в конце нужно вызывать её же с параметром (-1). Она при этом ничего не передаёт, а просто ждёт завершения передачи последнего байта. После этого уже можно обратно вручную устанавливать вывод ~CS в еденицу (_OFF_CS_ADS1218).
Если не выжимать из процессора максимум скорости, то можно было бы сделать немного попроще. Но мне так больше нравится.
Если нужно просто выкинуть в SPI 6 байт то вот пример:
void Write6bytesSPI(uByte *ptr)
{
_ON_CS_ADS1218;
txByteSPI(*ptr++);
for (uInt i=0; i<5; i++) // здесь выкинуть именно 5, а не 6 байт. т.к. один уже выкинут
rxtxByteSPI(*ptr++);
rxtxByteSPI(-1); // завершение передачи
_OFF_CS_ADS1218;
}
Кстати, процедура (rxtxByteSPI0(long byte)) передаёт новый байт в SPI, но возвращает как бы предыдущий принятый байт. Осторожно!
GetSmart
May 9 2006, 20:07
glebka
Возможно мне показалось, но возможно у вас SPI настроен на 16 бит, а записываете вы в него байты. Если это так и сначала передаются старшие биты, то первые 8 старших бит как бы не видно. А chip select, не понимаю, аппаратный что ли? Вроде не видел таких, если только это не SSEL.
glebka
May 10 2006, 10:09
У меня SPI init так: может что не так
void SPI_Init(unsigned char BitsPerTransfer)
{
volatile unsigned int data_temp;
unsigned char i;
// Enable peripheral clocks for SPI mode
AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1 << AT91C_ID_SPI ) ;
// Configure Periphery I/O, SPI mode enable.
AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,AT91C_PA11_NPCS0 |AT91C_PA13_MOSI | AT91C_PA14_SPCK | AT91C_PA12_MISO,AT91C_PA9_NPCS1|AT91C_PA10_NPCS2);
AT91F_SPI_Enable(AT91C_BASE_SPI);
// Mode register (Mode:Master/Slave), Peripherial select (0-Fixed,1-variable),Delay between chip selects)
//AT91C_BASE_SPI->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_PS_VARIABLE | (AT91C_SPI_DLYBCS & (0x15<<24));
AT91C_BASE_SPI->SPI_MR = 0x15000003;
AT91C_BASE_SPI->SPI_IER = AT91C_SPI_RDRF | AT91C_SPI_MODF | AT91C_SPI_OVRES;
AT91C_BASE_SPI->SPI_CSR[0]= AT91C_SPI_NCPHA|(AT91C_SPI_BITS & AT91C_SPI_BITS_8)|(AT91C_SPI_SCBR & (0x15 <<8 )) | (AT91C_SPI_DLYBS & (0x5 << 16))|(AT91C_SPI_DLYBCT &(0x20<< 24));
AT91C_BASE_SPI->SPI_CSR[1]= AT91C_SPI_NCPHA|(AT91C_SPI_BITS & AT91C_SPI_BITS_8)|(AT91C_SPI_SCBR & (0x15 <<8 )) | (AT91C_SPI_DLYBS & (0x5<< 16))|(AT91C_SPI_DLYBCT & (0x20<< 24));
AT91C_BASE_SPI->SPI_CSR[2]= AT91C_SPI_NCPHA|(AT91C_SPI_BITS & AT91C_SPI_BITS_8)|(AT91C_SPI_SCBR & (0x15 <<8 )) | (AT91C_SPI_DLYBS & (0x5 << 16))|(AT91C_SPI_DLYBCT &(0x20<< 24));
AT91F_PDC_Open((AT91PS_PDC) &(AT91C_BASE_SPI->SPI_RPR));
data_temp = AT91C_BASE_SPI->SPI_RDR; // Read data from Receive Data Register for prevent Overrun error
}
Edmundo
May 10 2006, 19:26
Итак, я провел анализ на работе, у меня, как и предполагалось, "виноват" передатчик. SAM'овский SPI отрабатывает на прием все как задумано. Могу привести свои исходники, но они для Slave-режима и только на прием (без передачи). Вряд ли Вам будет это интересно.
Однако для справки могу сказать, что когда писал свою программу, ориентировался на пример
отсюда. Скорректировал под себя, разумеется (пришлось подробно ознакомиться с даташитом), но заработало с первого раза (SPI под ARM вообще делаю первый раз

).
glebka
May 12 2006, 08:22
Благодарю Edmundo, GetSmart. но я делаю сделал всё правильно.Обнаружил,что в DEBUG режиме и когда устройство работает самостоятельно - картинка разная, причем при самостоятельной работе такая какя должна быть.
Пользуюсь IAR+ j-link. При отладке программу загружаю в флеш.Если не секркт почему картина такая разня.Может не успевает дебаггер?
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.