|
|
  |
проблемы с передачей по spi, sam7x+gcc |
|
|
|
Aug 10 2007, 06:35
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Начал разбираться с spi на этом контроллере(Evalution Board at91sam7x-ek) и наткнулся на такую проблему. Есть в нём такой режим, удерживать CS в активном состоянии, после окончания передачи. Инициализирую SPI слудующим образом Код /* Configure PIOs for SPI */ AT91C_BASE_PIOA->PIO_ASR = AT91C_PA12_SPI0_NPCS0 | AT91C_PA16_SPI0_MISO | AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; AT91C_BASE_PIOA->PIO_BSR = 0; AT91C_BASE_PIOA->PIO_PDR = AT91C_PA12_SPI0_NPCS0 | AT91C_PA16_SPI0_MISO | AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; //enable the clock of SPI AT91C_BASE_PMC->PMC_PCER = 1<<AT91C_ID_SPI0; // инициализация spi // сброс и разрешение AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIDIS | AT91C_SPI_SWRST; // установка моды работы spi master, first peripherial active AT91C_BASE_SPI0->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_LLB; // параметры общения с устройством на CS0 // скорость spi 24 МГц, задержка перед выдачей тактовой 300 нс. AT91C_BASE_SPI0->SPI_CSR[0] = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | (0x02 << 8) | (0x0F << 16);// | AT91C_SPI_CSAAT; // запрещаю все прерывания AT91C_BASE_SPI0->SPI_IDR = 0xFFFFFFFF; AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN; процедура отправки байта, крутится в основном цикле (запускается раз в 1 секунду) Код static unsigned char temp = 0; temp++; AT91C_BASE_SPI0->SPI_TDR = temp; так вот в чём проблема, когда добавляю бит AT91C_SPI_CSAAT (чтобы CS оставался активным) у меня передаётся один байт, псоле этого признак того, что передатчик пустой не появляется и запись в регистр SPI_TDR не приносит никакого эффекта. Как только убираю бит AT91C_SPI_CSAAT всё начинает работать нормально. Кто-нибудь сталкивался с таким эффектом.? Что я делаю не так? Как работать с устройствами, для сеанса обмена с которыми нужно удерживать CS активным (таже атмеловская флэшка на плате)? И как себя ведёт CS в фиксированной моде, нужен ли ему AT91C_SPI_CSAAT, перестаёт ли он быть активным после передачи? З.Ы, SPI работает сам на себя по локальной внутренней петле AT91C_SPI_LLB. При работе на внешнее устройство тот же эффект.
|
|
|
|
|
Aug 10 2007, 15:11
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
После всех сношений смог добиться странных результатов: Ведёт себя очень странно. CS на высоких частотах делает неактивным после каждого сеанса связи, уменьшаю тактовую частоту и spi начинает делать cs неактивным через 1 мс. Есть большое подозрение, что просто где-то внутри логика начинает не успевать срабатывать. Так что стрёмно работать в таком режиме. Решил попробовать через DMA контроллер. Заработало так как хотел. Отправляет n байт при одной активности CS. Флэшка на плате ожила и отвечает. Причем DMA контроллеру вообще пофик усьановлен ли бит CSAAT или нет. И с ним и без него работает одинакого. К стати как Вы умудрились запустить под управлением CS как обыкновенных выходов. Все мои усилия приводили к тому, что выходы начинали работать как надо, но умирал spi напрочь.  Танцы с бубном не помогли и я забил на попытки. Если не секрет, то поделитесь тайным знанием настройки пинов и spi в таком режиме, так чтобы spi не умирал.
|
|
|
|
|
Aug 14 2007, 09:04
|
Местный
  
Группа: Свой
Сообщений: 263
Регистрация: 2-02-07
Из: CN, Ukraine
Пользователь №: 24 970

|
не секрет. вот прямо из исходника (тут еще может где-то попасться обработка внутреннего протокола, но суть понятна будет) Код void SPI_Connect( PSPIPort self ) { // CHECKING AND CONFIGURING if (self->BASE_SPI == AT91C_BASE_SPI0) { self->SPI_ID = AT91C_ID_SPI0; self->BASE_SPI_PDC = AT91C_BASE_PDC_SPI0; /// PIO #ifdef SAM7X AT91F_PIO_CfgPeriph( AT91C_BASE_PIOA, // PIO controller base address AT91C_PA17_SPI0_MOSI | AT91C_PA16_SPI0_MISO | AT91C_PA18_SPI0_SPCK , // Peripheral A 0); // Peripheral B #else AT91F_PIO_CfgPeriph( AT91C_BASE_PIOA, // PIO controller base address AT91C_PA13_MOSI | AT91C_PA14_SPCK |AT91C_PA12_MISO, // Peripheral A 0); // Peripheral B #endif // registering processor _spiports [ 0 ] = self; } #ifdef SAM7X if (self->BASE_SPI == AT91C_BASE_SPI1) { self->SPI_ID = AT91C_ID_SPI1; self->BASE_SPI_PDC = AT91C_BASE_PDC_SPI1; // only SAM7X has 2nd SPI AT91F_PIO_CfgPeriph( AT91C_BASE_PIOA, // PIO controller base address 0, // Peripheral A AT91C_PA22_SPI1_SPCK | AT91C_PA23_SPI1_MOSI | AT91C_PA24_SPI1_MISO); // Peripheral B // registering processor _spiports [ 1 ] = self; } #endif if (self->SPI_ID == 0) return; /////////////////////////////////////////////////////////// // enable clock AT91F_PMC_EnablePeriphClock( AT91C_BASE_PMC, ((unsigned int) 1 << self->SPI_ID)); AT91F_SPI_Reset (self->BASE_SPI); if (self->slavemode) { AT91F_SPI_CfgMode( self->BASE_SPI, AT91C_SPI_PS_FIXED | AT91C_SPI_MODFDIS | ((unsigned int)(0x00<<16) & AT91C_SPI_PCS)); } else { AT91F_SPI_CfgMode( self->BASE_SPI, AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED | AT91C_SPI_MODFDIS | ((unsigned int)(0x00<<16) & AT91C_SPI_PCS)); } // reset PDC channels self->BASE_SPI_PDC->PDC_TPR = 0; self->BASE_SPI_PDC->PDC_TCR = 0; self->BASE_SPI_PDC->PDC_RPR = 0; self->BASE_SPI_PDC->PDC_RCR = 0; self->BASE_SPI_PDC->PDC_PTCR = 0; // configure self->BASE_SPI->SPI_CSR[0]= AT91C_SPI_BITS_8 | ((unsigned int) self->clockdivider << 8)| // (SPI) Serial Clock Baud Rate ((unsigned int) 0x00 << 16)| // (SPI) Delay Before SPCK ((unsigned int) SPI_DELAY_BETWEEN_TRANSFERS << 24); // (SPI) Delay Between Consecutive Transfers AT91F_SPI_Enable(self->BASE_SPI); // Init CS pins AT91C_BASE_PIOA->PIO_PER = DEV_CS_ALL_A; AT91C_BASE_PIOA->PIO_OER = DEV_CS_ALL_A;
#ifdef SAM7X AT91C_BASE_PIOB->PIO_PER = DEV_CS_ALL_B; AT91C_BASE_PIOB->PIO_OER = DEV_CS_ALL_B; #endif // clearing remote side buffers #ifdef SPI_CLEAR_REMOTE_BUFFERS #ifndef SPI_SLAVE if (! self->slavemode ) { memset( self->TXdata, SPI_CLEAR_BUFFERS, SPI_BUFFER_LENGTH ); for (unsigned char zz = 0; zz < SPI_DEVICE_COUNT; zz++ ) { __SPI_Send( self, zz, self->TXdata, SPI_BUFFER_LENGTH, 0 ); } } #endif #endif __SPI_UnSelectAll(); /// CONNECT SPI OKAY return; } и отправка данных Код short __SPI_Send( PSPIPort self, unsigned char devnum, unsigned char * data, unsigned short count, unsigned short timeout ) { if (!timeout) timeout = _SPI_TIMEOUT; if (!(count)) return SPI_ERROR; __SPI_Select( devnum ); OSSemSet(self->ENDTXSemaphore, 0, &self->last_error);
unsigned long sr = self->BASE_SPI->SPI_SR;
// preparing buffer self->BASE_SPI_PDC->PDC_TPR = (unsigned int) (char *)data; self->BASE_SPI_PDC->PDC_TCR = count;
// enabling SEND PDC // reset IRQ self->BASE_SPI->SPI_IDR = (SPI_PDC_TX_FINISHED_FLAG ); sr = self->BASE_SPI->SPI_SR = 0; self->BASE_SPI->SPI_IER = (SPI_PDC_TX_FINISHED_FLAG ); self->BASE_SPI_PDC->PDC_PTCR = AT91C_PDC_TXTEN; OSSemPend(self->ENDTXSemaphore, timeout , &self->last_error); self->BASE_SPI->SPI_IDR = (SPI_PDC_TX_FINISHED_FLAG );
// need to read it - SPI SAM7 bug (unsigned long)self->BASE_SPI->SPI_RDR; // reading status to clear it (unsigned long)self->BASE_SPI->SPI_SR; (unsigned long)self->BASE_SPI->SPI_RDR; __SPI_UnSelectAll(); // disabling SEND PDC self->BASE_SPI_PDC->PDC_PTCR = AT91C_PDC_TXTDIS; short res = count - (self->BASE_SPI_PDC->PDC_TCR); (void)data;
return res; } и выбор чипа Код //////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////// __inline void __SPI_Select( unsigned char devnum ) { #ifdef SPI_SLAVE (void)devnum; return; #else if (devnum > 8) return; #ifdef SPI_STAY_SELECTED if (devnum == spi_last_selected) return; devnum = spi_last_selected; #endif // first disabling all AT91C_BASE_PIOA->PIO_SODR = DEV_CS_ALL_A; AT91C_BASE_PIOA->PIO_CODR = DEV_CS_A[ devnum ]; #ifdef SAM7X AT91C_BASE_PIOB->PIO_SODR = DEV_CS_ALL_B; AT91C_BASE_PIOB->PIO_CODR = DEV_CS_B[ devnum ]; #endif
#endif // SPI_SLAVE } //////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////// __inline void __SPI_UnSelect( unsigned char devnum ) { #ifdef SPI_SLAVE
(void)devnum; return; #else
if (devnum > 8) { return; } // disabling all AT91C_BASE_PIOA->PIO_SODR = DEV_CS_A[ devnum ];
#ifdef SAM7X AT91C_BASE_PIOB->PIO_SODR = DEV_CS_B[ devnum ]; #endif // SAM7X
#endif //SPI_SLAVE }
|
|
|
|
|
Jan 9 2008, 07:28
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Цитата(prottoss @ Jan 8 2008, 13:57)  Привет всем! Осваиваю SPI на AT91SAM7X256 - боард от Argussoft - AS-SAM7X - аналог AT91SAM7X-EK. Сотврил драйвер для SPI0 - можно менять софтовое дергание CSx на хардварное - но не работает!!! Вроде уяснил, то, что написано в топике, но чего то не допонял  Почитай errata, там очень много всего про SPI написанно. Цитата(prottoss @ Jan 8 2008, 13:57)  Кстати, с хардварным SPI, если ставить точку останова перед процедурой передачи - то данные передаются! В программе - нет! Хэлп-хэлп! Не понятно, если точка останова перед процедурой передачи, то как данные передаются
|
|
|
|
|
Jan 9 2008, 12:53
|

Местный
  
Группа: Свой
Сообщений: 370
Регистрация: 7-11-06
Пользователь №: 22 035

|
Вот как у меня запускается приём или передача Код
if (SPI_WRITE == DiscriptorSpi1->rwHeader) { AT91C_BASE_SPI1->SPI_TPR = (uint32_t)(DiscriptorSpi1->pHeader); AT91C_BASE_SPI1->SPI_TCR = DiscriptorSpi1->bSizeHeader; AT91C_BASE_SPI1->SPI_IER = AT91C_SPI_TXBUFE; } else // SPI_READ { uint32_t dummy; while (AT91C_BASE_SPI1->SPI_SR & AT91C_SPI_RDRF) dummy = AT91C_BASE_SPI1->SPI_RDR; AT91C_BASE_SPI1->SPI_RPR = (uint32_t)(DiscriptorSpi1->pHeader); AT91C_BASE_SPI1->SPI_RCR = DiscriptorSpi1->bSizeHeader; AT91C_BASE_SPI1->SPI_IER = AT91C_SPI_RXBUFF; AT91C_BASE_SPI1->SPI_TPR = (uint32_t)(DiscriptorSpi1->pHeader); AT91C_BASE_SPI1->SPI_TCR = DiscriptorSpi1->bSizeHeader; } настраивается примерно также как и у вас. Различие в том, что я не в цикле опрашиваю /* Wait for transmitter/receiver complete */ while(0 == (AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_ENDTX)); while(0 == (AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_ENDRX)); а обрабатываю прерывание от BUFF empty и full. Попробуйте тоже ориентироваться на эти события. И ещё PDC у меня разрешается сразу при настройке, а транзакция запускается записью в регистр SPI_TCR.
|
|
|
|
|
Jan 9 2008, 13:17
|

Профессионал
    
Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555

|
Цитата(prottoss @ Jan 9 2008, 16:05)  Спасибо, буду пробовать... Хотя мне не понятна разница между ожиданием флагов окончания приема-передачи и сигналом от обработчика прерывания на чисто физическом уровне... А вы почитайте errata, у них как раз бага с CSAAT и LASTXFER, да и вообще что бы запустить аппаратные чипселекты надо поплясать с бубном, на разных семействах разные баги и особенности. Проще всего взять осцилограф и смотреть как работает. Я выбрал такой алгоритм, он правильно работатет везде - посылаю через DMA (все данные гарантировано уходят при низком CS) что бы дернуть CS или переключится на другой надо убедится что DMA пуст и передача завершена ((*AT91C_SPI_SR & (AT91C_SPI_TXEMPTY | AT91C_SPI_TXBUFE))== (AT91C_SPI_TXEMPTY | AT91C_SPI_TXBUFE)) Отсальные варианты то на SAM7X, то на SAM7S работают криво.
|
|
|
|
|
Jan 9 2008, 14:26
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(KRS @ Jan 9 2008, 20:17)  Отсальные варианты то на SAM7X, то на SAM7S работают криво. БОЛЬШОЕ спасибо за разъяснение проблемы - теперь более-менее встало все на свои места - все читается-пишется, НО опять же с аппаратным CS Программный так и не могу заставить работать... Осциллографа, к сожалению, счас под рукой нет, но нога CS программно дрыгается - проверил тестером Вот код инициализации: Код void SPI_Init(void) { /* Configure PIOs */ AT91C_BASE_PIOA->PIO_ASR = #ifndef SPI_SOFT_CHIP_SELECT AT45DB_CS_LINE | /* Configure CS line SPI#0 */ #endif /* #ifdef SPI_SOFT_CHIP_SELECT */ AT91C_PA16_SPI0_MISO | /* MISO SPI#0 */ AT91C_PA17_SPI0_MOSI | /* MOSI SPI#0 */ AT91C_PA18_SPI0_SPCK; /* SCK SPI#0 */
AT91C_BASE_PIOA->PIO_PDR =
#ifndef SPI_SOFT_CHIP_SELECT AT45DB_CS_LINE | /* Configure CS line SPI#0 */ #endif /* #ifdef SPI_SOFT_CHIP_SELECT */ AT91C_PA16_SPI0_MISO | /* MISO SPI#0 */ AT91C_PA17_SPI0_MOSI | /* MOSI SPI#0 */ AT91C_PA18_SPI0_SPCK; /* SCK SPI#0 */
/* Enable CLock */ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_SPI0;
/* Reset the SPI */ AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SWRST;
/* Configure SPI in Master Mode with No CS selected !!! */ AT91C_BASE_SPI0->SPI_MR = (24 << AT45DB_DLYBCS) | AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS;
/* Configure CS1 line */ UINT32 csr = (AT91C_SPI_CPOL | ((BOARD_CPU_GetClkFreq() / AT45DB_SPI_CLK) << 8)| (AT91C_SPI_DLYBS & (AT45DB_DLYBS << 16)) | (AT91C_SPI_DLYBCT & (AT45DB_DLYBCT << 24)) ); AT91C_BASE_SPI0->SPI_CSR[1] = csr;
#ifdef SPI_SOFT_CHIP_SELECT /* Configure CS1 in PIO mode (bug fix for SAM7X256) */ AT91C_BASE_PIOA->PIO_PER = AT45DB_CS_LINE; /* Enable line */ AT91C_BASE_PIOA->PIO_OER = AT45DB_CS_LINE; /* Enable output */ AT91C_BASE_PIOA->PIO_IDR = AT45DB_CS_LINE; /* Disable interrupt */
/* Enable peripheral clock */ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_PIOA;
/* Chip deselect */ CHIP_OFF(AT45DB_CS_LINE); #endif /* #ifdef SPI_SOFT_CHIP_SELECT */
/* Configure SPI CS1 for Serial DataFlash AT45DBxx */ AT91C_BASE_SPI0->SPI_MR &= ~(0x2 << 16); /* clear bit CS line bit */
/* SPI_Enable */ AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN;
/* Disable Transmitter and Reseiver transfers and clear DMA buffers */ AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTDIS + AT91C_PDC_RXTDIS; AT91C_BASE_SPI0->SPI_RCR = 0; AT91C_BASE_SPI0->SPI_TCR = 0; } Вот код обмена данными: Код void SPI_Xfer(SPI_XDesc_t *desc) { CHIP_OFF(AT45DB_CS_LINE); /* Chip deselect */ CHIP_ON(AT45DB_CS_LINE); /* Chip select */
/* read rx data register and status register for clear previos transfers flag */ (UINT32)AT91C_BASE_SPI0->SPI_RDR; (UINT32)AT91C_BASE_SPI0->SPI_SR; (UINT32)AT91C_BASE_SPI0->SPI_RDR; /* Initialize the Transmit and Receive Pointers */ AT91C_BASE_SPI0->SPI_RPR = (UINT32)desc->rx_curr_data; AT91C_BASE_SPI0->SPI_TPR = (UINT32)desc->tx_curr_data;
/* Intialize the Transmit and Receive Counters */ AT91C_BASE_SPI0->SPI_RCR = desc->rx_curr_len; AT91C_BASE_SPI0->SPI_TCR = desc->tx_curr_len; /* Start transfer */
if(desc->tx_next_len != 0) { /* Initialize the Next Receive Pointer and Next Receive Counter */ AT91C_BASE_SPI0->SPI_RNPR = (UINT32)desc->rx_next_data; AT91C_BASE_SPI0->SPI_RNCR = desc->rx_next_len; /* Initialize the Next Transmit Pointer and Next Transmit Counter */ AT91C_BASE_SPI0->SPI_TNPR = (UINT32)desc->tx_next_data; AT91C_BASE_SPI0->SPI_TNCR = desc->tx_next_len; }
/* Start transfer */ AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_RXTEN + AT91C_PDC_TXTEN;
/* Wait for transmitter/receiver complete */ #if 0 while(0 == (AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_ENDTX)); while(0 == (AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_ENDRX)); #endif
/* Wait for DMA empty */ while((AT91C_BASE_SPI0->SPI_SR & (AT91C_SPI_TXEMPTY | AT91C_SPI_TXBUFE | AT91C_SPI_RXBUFF)) != (AT91C_SPI_TXEMPTY | AT91C_SPI_TXBUFE | AT91C_SPI_RXBUFF)); /* Disable Transmitter and Reseiver transfers */ AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTDIS + AT91C_PDC_RXTDIS; /* Chip deselect */ CHIP_OFF(AT45DB_CS_LINE); /* Chip deselect */ }
--------------------
|
|
|
|
|
Feb 13 2008, 07:49
|

Группа: Новичок
Сообщений: 8
Регистрация: 30-10-07
Из: Петрозаводск
Пользователь №: 31 873

|
Сейчас вот разбираюсь с SPI, чтоб не плодить темы, спрошу здесь  . Составляю УСЛОВИЕ ГОТОВНОСТИ SPI к передаче-приему, как должен выглядеть статус-регистр (SPI_SR)? Первое, что пришло в голову - это TXEMPTY==1 (регистр и буфер передачи пусты), но так не срабатывает (видимо при начальной загрузке здесь=0). Далее, пришел к такому: TXBUFE == 1 --- буфер-передатчик опустошен RXBUFF == 0 --- буфер-приемник не заполнен TDRE == 1 --- регистр для передачи пуст RDRF == 0 --- регистр приема не заполнен но почему-то работает при RXBUFF == 1 (остальные 3 условия без изменений). Как наиболее полно должно выглядеть условие готовности SPI, чтоб в нем точно ничего нету, можно запускать передачу-прием ?
--------------------
~Venerium Rerum Omnium~
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|