Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Не работает SPI
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
yshur
Используем ARM AT91M42800 и АЦП с SPI интерфейсом.
Драйвер для чтение АЦП отказывается работать, если поместить чтение АЦП в прерывание от таймера (на ножках SPI ничего нет).
Вне прерывания драйвер работает нормально.

В чем может быть проблема?
aaarrr
Изложите проблему более подробно, и приведите код "драйвера" АЦП и прерывания таймера. А то так гадать придется долго.
yshur
Цитата(aaarrr @ Jan 20 2007, 13:37) *
Изложите проблему более подробно, и приведите код "драйвера" АЦП и прерывания таймера. А то так гадать придется долго.

Вот драйвер чтения АЦП :



typedef struct _SPIA_Desc
{
const SpiDesc * spi_desc ;
u_int mode_spi ;
}SPIA_Desc ;
/*===============================================================================
===================
LOCAL MACROS
================================================================================
==================*/

/*===============================================================================
===================
LOCAL VARIABLES
================================================================================
==================*/

/*===============================================================================
===================
GLOBAL VARIABLES
================================================================================
==================*/
SPIA_Desc spia_dev = {0};
/*===============================================================================
===================
LOCAL FUNCTIONS
================================================================================
==================*/

/*===============================================================================
===================
GLOBAL FUNCTIONS
================================================================================
==================*/

/*===============================================================================
===================

FUNCTION: Data_Processor_Handler()

DESCRIPTION:

ARGUMENTS PASSED:

RETURN VALUE:
None

PRE-CONDITIONS:
None

POST-CONDITIONS:

IMPORTANT NOTES:
None
================================================================================
==================*/
ERROR_CODE HAPI_SPIA_Init(void )
{
ERROR_CODE ret_value = TRUE;

spia_dev.spi_desc = &SPIA_DESC;

spia_dev.mode_spi = (SPI_MASTER
//#ifdef _DEBUG_ATMEL
| SPI_NPCS0_USED
| SPI_NPCS1_USED
| SPI_NPCS2_USED);
/*
#else
| SPI_NPCS0_USED | SPI_NPCS0_OPENDRAIN
| SPI_NPCS1_USED | SPI_NPCS1_OPENDRAIN
| SPI_NPCS2_USED | SPI_NPCS2_OPENDRAIN);
#endif
*/
// HAPI_GPIO_Set(LED1);

return ret_value;
}
/*===============================================================================
===================

FUNCTION: Data_Processor_Handler()

DESCRIPTION:

ARGUMENTS PASSED:

RETURN VALUE:
None

PRE-CONDITIONS:
None

POST-CONDITIONS:

IMPORTANT NOTES:
None
================================================================================
==================*/
ERROR_CODE HAPI_SPIA_On(void )
{
ERROR_CODE ret_value = TRUE;
u_int status;

at91_spi_open ( spia_dev.spi_desc, spia_dev.mode_spi );

status = at91_spi_get_status (spia_dev.spi_desc);

// SPI mode reg
spia_dev.spi_desc->spi_base->SP_MR = SP_MSTR;
spia_dev.spi_desc->spi_base->SP_MR |= 0x0A000000;

// SPI CS regs
spia_dev.spi_desc->spi_base->SP_CSR[0] = 0x0A000000 | 0x00020000 | 0x00000a00 | SP_CPOL | SP_NCPHA | SP_BITS_14;
spia_dev.spi_desc->spi_base->SP_CSR[1] = 0x0A000000 | 0x00020000 | 0x00000a00 | SP_CPOL | SP_NCPHA | SP_BITS_14;
spia_dev.spi_desc->spi_base->SP_CSR[2] = 0x0A000000 | 0x00020000 | 0x00000a00 | SP_CPOL | SP_NCPHA | SP_BITS_14;


if(status & SP_SPIENS)
{
// HAPI_GPIO_Set(LED2);
}

return ret_value;
}
/*===============================================================================
===================

FUNCTION: Data_Processor_Handler()

DESCRIPTION:

ARGUMENTS PASSED:

RETURN VALUE:
None

PRE-CONDITIONS:
None

POST-CONDITIONS:

IMPORTANT NOTES:
None
================================================================================
==================*/
ERROR_CODE HAPI_SPIA_Off(void )
{
ERROR_CODE ret_value = TRUE;
u_int status;

at91_spi_close ( spia_dev.spi_desc );

status = at91_spi_get_status (spia_dev.spi_desc);

if(!(status & SP_SPIENS))
{
//HAPI_GPIO_Reset(LED2);
}

return ret_value;
}
/*===============================================================================
===================

FUNCTION: Data_Processor_Handler()

DESCRIPTION:

ARGUMENTS PASSED:

RETURN VALUE:
None

PRE-CONDITIONS:
None

POST-CONDITIONS:

IMPORTANT NOTES:
None
================================================================================
==================*/
ERROR_CODE HAPI_SPIA_Read(UINT8 chip_idx, UINT16 *data)
{
ERROR_CODE ret_value = TRUE;
short t_data = 0;
u_int mode_spi;
u_int status;

mode_spi = spia_dev.spi_desc->spi_base->SP_MR;

mode_spi &= ~(SP_PCS);

switch(chip_idx)
{
case(0):
mode_spi |= SP_PCS0;
break;
case(1):
mode_spi |= SP_PCS1;
break;
case(2):
mode_spi |= SP_PCS2;
break;
default:
mode_spi |= SP_PCS0;
break;
}

spia_dev.spi_desc->spi_base->SP_MR = mode_spi;

// HAPI_GPIO_Set(LED3);

at91_spi_write( spia_dev.spi_desc, &t_data );

do
{
status = at91_spi_get_status (spia_dev.spi_desc);
}
while(!(status & SP_TDRE));

do
{
status = at91_spi_get_status (spia_dev.spi_desc);
}
while(!(status & SP_RDRF));

at91_spi_read( spia_dev.spi_desc, &t_data );

//HAPI_GPIO_Reset(LED3);

*data = (UINT16)t_data;

return ret_value;
}
/*===============================================================================
===================

FUNCTION: HAPI_SPIA_FastRead()

DESCRIPTION:

ARGUMENTS PASSED:

RETURN VALUE:
None

PRE-CONDITIONS:
None

POST-CONDITIONS:

IMPORTANT NOTES:
None
================================================================================
==================*/
ERROR_CODE HAPI_SPIA_FastRead(UINT8 chip_idx, UINT16 *data)
{
ERROR_CODE ret_value = TRUE;
short t_data = 0;
u_int mode_spi;
u_int status;
u_int i;

mode_spi = spia_dev.spi_desc->spi_base->SP_MR;

mode_spi &= ~(SP_PCS);

switch(chip_idx)
{
case(0):
mode_spi |= SP_PCS0;
break;
case(1):
mode_spi |= SP_PCS1;
break;
case(2):
mode_spi |= SP_PCS2;
break;
default:
mode_spi |= SP_PCS0;
break;
}

spia_dev.spi_desc->spi_base->SP_MR = mode_spi;

// Write data
spia_dev.spi_desc->spi_base->SP_TDR = *data ;

// Check that data has been sent
while(!(spia_dev.spi_desc->spi_base->SP_SR & SP_TDRE));

// Check that data has been received
while(!(spia_dev.spi_desc->spi_base->SP_SR & SP_RDRF));

// Read data
*data = (UINT16)(spia_dev.spi_desc->spi_base->SP_RDR & SP_RD);

for(i = 0; i < 80; i++);

return ret_value;
}

Предварительно инициализирую АЦП функциями HAPI_SPIA_Init и HAPI_SPIA_On

Функция обработчика прерывания:
__irq void sys_ADC_Timer_irq_handler_CH1(void)
{
u_int readkey;
UINT16 buf;
;
readkey=TC5_SR;

HAPI_SPIA_FastRead(ADC_CHANNEL_1, &buf );

AIC_EOICR = 0xFFFFFFFF;
}

Проблема в том что елси вызываю HAPI_SPIA_FastRead из обработчика прерывания , реально передачи данных по SPI не происходит.
Если читать АЦП без всяких прерываний все нормально.
aaarrr
Цитата(yshur @ Jan 20 2007, 14:22) *
Проблема в том что елси вызываю HAPI_SPIA_FastRead из обработчика прерывания , реально передачи данных по SPI не происходит.
Если читать АЦП без всяких прерываний все нормально.

А без прерываний как читаете - при помощи HAPI_SPIA_FastRead, или HAPI_SPIA_Read?
AlexBoy
Цитата(yshur @ Jan 20 2007, 12:29) *
Используем ARM AT91M42800 и АЦП с SPI интерфейсом.
Драйвер для чтение АЦП отказывается работать, если поместить чтение АЦП в прерывание от таймера (на ножках SPI ничего нет).
Вне прерывания драйвер работает нормально.

В чем может быть проблема?


Проверьте вызывается ли вообще это прерывание (помигать светодиодом), и если вызывается то может слишком часто, не успевает пройти предыдущий байт, смотрю сейчас стоит делитель скорости 10. И еще у меня проверки немного в другом порядке, попробуйте так:

//----------------------------------------------------------------------------
BYTE AT91F_ByteSPI(int channel, BYTE data)
{
AT91PS_SPI pSPI = SpiChannels[channel].spi_base;
while(!(pSPI->SPI_SR & AT91C_SPI_TDRE)); // ожидание пока буфер передачи не пустой
pSPI->SPI_TDR = data; // запись в регистр передачи
while(!(pSPI->SPI_SR & AT91C_SPI_RDRF)); // ожидание пока буфер приема пустой
data = pSPI->SPI_RDR; // чтение из регистра приема
return data;
}
andrvisht
Поскольку АРМ только начал изучать решил попробовать Keil 3.51
Задача состоит в работе SPI на LPC2294. За основу был взят пример из книги Тревора Мартина слегка переделанный под задачу.
делаем инициализацию:
Код
  PINSEL1 = 0x000002A8;        //Enable SPI1 pins
  IODIR1     =    0x00000000;        //Enable Chipselect pin as output
  VICVectCntl0 = 0x0000002B;          //Select a priority slot for a given interrupt (A - interrupt SPI0)
  VICVectAddr0 = (unsigned)SPI_ISR;    //Pass the address of the IRQ into the VIC slot
  VICIntEnable = 0x00000800;            //Enable interrupt SPI1

Функция записи данных контроллером
Код
void TxSPI(unsigned char *pData, unsigned char SPICount)
{
  unsigned char i;
  CountTxSPI = SPICount; // загрузка счетчика переданных байт
  for(i = SPICount; i > 0;) // перегрузка данных в буфер SPI
  {
    BufSPI[--i] = *pData++;
  }
  pSPI = &BufSPI[SPICount-1]; // указатель на начало передачи
  S1SPCCR = 0xFF;
  S1SPCR = (1<<SPIE)|(1<<MSTR)|(0<<CPOL)|(0<<CPHA);
  S1SPDR = *pSPI;
}

и собственно обработка прерывания
Код
void SPI_ISR(void) __irq
{
  *pSPI = S1SPDR; // чтение данных в буфер
  if (CountTxSPI > 1)
  {
    S1SPDR = *(--pSPI);
    CountTxSPI--;
  }
  else
  {
    CountTxSPI = 0;
    PCONP &= ~(1<<PCSPI1); // выключение SPI
  }
  S1SPINT =    0x01;
  VICVectAddr = 0x00000000;
  return;
}

И вот получается что в симуляции все нормально, а в реальном железе прерывание срабатывает только 1 раз.
Пример из которого переделывалось ведет себя аналогично. PLL не использую, кварц 14.7456MHz
Видимо симулятор что то не договаривает, но вот что ?
Сергей Борщ
Цитата(&-rey @ Apr 17 2007, 14:24) *
делаем инициализацию:
У вас ведь дальше очень красиво написано:
Код
S1SPCR = (1<<SPIE)|(1<<MSTR)|(0<<CPOL)|(0<<CPHA);
Почему же вы тут пишете страшные шестнадцатиричные числа? Ведь можно голову сломать переводя их в биты
Код
  PINSEL1 = (2UL<<8) | (2UL<<6)|(2UL<<4)|(2UL<<2);        //Enable SPI1 pins
  VICVectCntl0 = (1<<VIC_SPI1) | (1<<5);          //Select a priority slot for a given interrupt (A - interrupt SPI1)
  VICVectAddr0 = (unsigned)SPI_ISR;    //Pass the address of the IRQ into the VIC slot
  VICIntEnable = (1UL<<VIC_SPI1);            //Enable interrupt SPI1

Цитата(&-rey @ Apr 17 2007, 14:24) *
и собственно обработка прерывания

1) Вы выключаете питание SPI после передачи (PCONP &= ~(1<<PCSPI1); ) а включения его обратно перед началом передачи я не вижу.
2) У вас нога SSEL настроена на ввод и подтянута снаружи к единице?
zltigo
Цитата(Сергей Борщ @ Apr 17 2007, 15:54) *
Почему же вы тут пишете страшные шестнадцатиричные числа?
Ведь можно голову сломать переводя их в биты

Если-бы только это, все жутковато написано sad.gif
Цитата
1) Вы выключаете питание SPI после передачи (PCONP &= ~(1<<PCSPI1); ) а включения его обратно перед началом передачи я не вижу.

До этого еще не дошло, пока поле первого-же прерывания
SPI Status Register не вычитывается.
andrvisht
Цитата(Сергей Борщ @ Apr 17 2007, 15:54) *
Почему же вы тут пишете страшные шестнадцатиричные числа? Ведь можно голову сломать переводя их в биты

Потому что Keil. Разработчики поленились и описали только регистры, на описание битов сил у них не хватило sad.gif Другое дело IAR, там все по человечески сделано, но решил опробовать Keil ввиду возможности симулить переферию. До нормального описания битов через #define пока не дошли руки.
Цитата
1) Вы выключаете питание SPI после передачи (PCONP &= ~(1<<PCSPI1); ) а включения его обратно перед началом передачи я не вижу.
2) У вас нога SSEL настроена на ввод и подтянута снаружи к единице?


да, это недосмотр. Просто в TXSPI были строки выключения SPI вначале и включение в конце, а потом я их устранил чтобы не захломлять код, удалил и эту строку из прерывания, а также настроил SSEL на вывод IODIR0 |= 1<<20;
Результат тот же, прерывание срабатывает только 1 раз. По косвенным признакам нога SCK1 (P0.17) в Z. Если посмотреть в отладке на PINSEL0 то там все в порядке, т.е. видно что к ногам прицеплен SPI1.
Сергей Борщ
Цитата(&-rey @ Apr 17 2007, 15:26) *
а также настроил SSEL на вывод IODIR0 |= 1<<20;
А вот этого делать нельзя, она должна быть настроена на вход и подтянута снаружи к 1:
Цитата
Note: LPC2119/2129/2194/2292/2294 configured to operate as SPI master MUST select
SSEL functionality on an apropriate pin and have HIGH level on this pin in order to act
as a master.
И про чтение статуса (S1SPSR), как заметил zltigo не забудьте.
andrvisht
Цитата(Сергей Борщ @ Apr 17 2007, 16:47) *
А вот этого делать нельзя, она должна быть настроена на вход и подтянута снаружи к 1: И про чтение статуса (S1SPSR), как заметил zltigo не забудьте.


Все понял, а я то на эту ногу уже Chip Select приделал smile.gif
Спасибо, все заработало как в симуляторе.
Сергей Борщ
Цитата(&-rey @ Apr 17 2007, 16:09) *
Все понял, а я то на эту ногу уже Chip Select приделал smile.gif
Я тоже sad.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.