Перейти к содержанию
    

SPI на ARM

Добрый день, коллеги!

 

Возникла проблема при работе с интерфейсом SSP на ARM LPC1769.

 

Для начала я инициализировал интерфейс:

 

1) В регистре PCONP - Power Control

2) PCLKSEL - Clock (поставил cclk/4)

3) PINSEL - выставил требуемые значения для CLK,SSEL,MISO,MOSI

4) SSP0CR0 - выставил 0x000F, что соответствует 16 битной передаче, CPOL=0 и CPHA=0

SSP0CR1 - выставил 0x0000, что соответствует режиму MASTER, затем выставил бит SSE=1 в этом регистре, что соответствует:

The SSP controller will interact with other devices on the serial bus. Software should write the appropriate control information to the other SSP registers and interrupt controller registers, before setting this bit.

5) SSP0CPSR - выставил второй бит.

 

Таким образом инициализация интерфейса SSP выглядит так:

void SSP0Init( void )
{
  uint8_t i;
  uint16_t Dummy=Dummy;        //Changed to uint16_t

  /* Enable AHB clock to the SSP0. */
  LPC_SC->PCONP |= (0x1<<21);

  /* Further divider is needed on SSP0 clock. Using default divided by 4 */
  LPC_SC->PCLKSEL1 &= ~(0x3<<10);

  /* P0.15~0.18 as SSP0 */
  LPC_PINCON->PINSEL0 &= ~(0x3UL<<30);
  LPC_PINCON->PINSEL0 |= (0x3UL<<30);
  LPC_PINCON->PINSEL1 &= ~((0x3<<0)|(0x3<<2)|(0x3<<4));
  LPC_PINCON->PINSEL1 |= ((0x2<<0)|(0x2<<2)|(0x2<<4));

  /* Set DSS data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 0, and SCR is 15 */
  LPC_SSP0->CR0 = 0x000F;
  
  LPC_SSP0->CR1 = 0x0000; //ADD by ME
  
  /* SSPCPSR clock prescale register, master mode, minimum divisor is 0x02 */
  LPC_SSP0->CPSR = 0x2;

  for ( i = 0; i < FIFOSIZE; i++ )
  {
    Dummy = LPC_SSP0->DR;        /* clear the RxFIFO */
  }

//  /* Master mode */
  LPC_SSP0->CR1 = SSPCR1_SSE;

  /* Set SSPINMS registers to enable interrupts */
  /* enable all error related interrupts */
  LPC_SSP0->IMSC = SSPIMSC_RORIM | SSPIMSC_RTIM;
  return;
}

 

При отладке видно, что все пины инициализированы как надо и SSP работает в формате SPI. В main добавил:

  for ( i = 0; i < 1000; i++ )
  {
  uint8_t *k; 
   
   k = (uint8_t *) i;
  sprintf(text, "0x%04X", k);
  GLCD_DisplayString (7, 8, 1, (unsigned char *)text);
   
  SSPSend( 0, (uint16_t *) text, 16);
  os_dly_wait (100);
  }

 

Однако SPI не работает, осциллограф показывает следующее post-51964-1342757355_thumb.png

(синий -MOSI, красный - CLK)

 

Функция передачи данных:

 

void SSPSend( uint32_t portnum, uint16_t *buffer, uint32_t Length )
{
  uint32_t i;
  uint16_t Dummy = Dummy;
    
  for ( i = 0; i < Length; i++ )
    {
/* Move on only if NOT busy and TX FIFO not full. */
      while ( (LPC_SSP0->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF );
      LPC_SSP0->DR = *buffer;
      buffer++;

      /* Wait until the Busy bit is cleared. */
      while ( LPC_SSP0->SR & SSPSR_BSY );

}
  
  return; 
}

 

Почему на осциллографе не видно сигналов CLK и MOSI по сути ни каких данных не выставляет, а только выдает импульсы напряжения?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Возникла проблема при работе с интерфейсом SSP на ARM LPC1769.

Нет времени вникать в чужой код. Возьмите соотв. примеры, поставляемые с Кейлом или ИАРом, и посмотрите, как они сделаны ...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нет времени вникать в чужой код. Возьмите соотв. примеры, поставляемые с Кейлом или ИАРом, и посмотрите, как они сделаны ...

Спасибо за совет, естественно первоначально я именно так и поступил, после чего и выявлена данная проблема и вынесена на всеобщее обсуждение в топик. Скорее всего, как мне кажется, дело лежит в обработке прерываний, так как при инициализации SPI я никак не обозначил обработчик прерываний, да и собственно саму процедуру прерываний для него не описал. Сейчас мучаюсь над совмещением обработчика прерываний с операционной системой, которая вертится на ядре (RTX Keil)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

мысли:

- поменять осциллограф (что это? USB-приставка?) или замедлить всё происходящее на порядок, а то и на два, снизив частоту SPI. Как заработает, можно потихоньку возвращать всё назад.

- в целях отладки удобнее отправлять не непонятный *text, а какие-то заранее известные значения, чтобы было понятно, что ждать на осциллографе.

- поддержу идею посмотреть примеры. SPI_Send обычно пишется с одним while'ом, но при этом с вычитыванием принятого (чтобы не найти граблей при работе SPI_Receive).

- прерывания для этого модуля совершенно необязательны. У меня всё прекрасно работает без них, более того, с прерываниями лично я написал бы гораздо медленнее и запутаннее (так, прикидки на пальцах).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

мысли:

- поддержу идею посмотреть примеры. SPI_Send обычно пишется с одним while'ом, но при этом с вычитыванием принятого (чтобы не найти граблей при работе SPI_Receive).

- прерывания для этого модуля совершенно необязательны. У меня всё прекрасно работает без них, более того, с прерываниями лично я написал бы гораздо медленнее и запутаннее (так, прикидки на пальцах).

 

С вычитыванием какого принятого? что то я не сообразил, это Вы про буфер? А в примерах используется прерывание, вот и подумал, что оно необходимо.

Изменено пользователем cinema_effect

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Нарыл пример от NXP. Да, что-то они замороченное написали, для демонстрации всего-всего.

 

На самом деле, всё крайне просто:

void SPI_Init(void)
{
LPC_SSP0->CR1 = 0x0000;			// Запрет работы SPI0

// SPI_SCR + 1 = Дополнительное (после SSP0CLKDIV и после SSP0CPSR) деление частоты = 1, 
//  Режим SPI = 0 (CPHA = 0, CPOL = 0), Формат кадра SPI, Кадр = 8 бит
LPC_SSP0->CR0 = 0x0007;

// Clock prescale, even values: 2..254
LPC_SSP0->CPSR = 0x0002;		// Минимальное значение; 18 МГц при частоте контроллера 36 МГц

LPC_SSP0->IMSC = 0x0000;		// Запрет все возможных источников прерывания от SPI0

// Включаем SPI0
LPC_SSP0->CR1 = 0x0002;

// Очистка FIFO
while( LPC_SSP0->SR & BIT(2) )	// Receive FIFO Not Empty
	LPC_SSP0->DR;

// На всякий случай сбросим м/с памяти
ACTIVE_SPI();
DEACTIVE_SPI();

return;
}

// Передает и в это же время принимает байт
uint8_t SendByteSPI (uint8_t data)
{
LPC_SSP0->DR = data;
while( LPC_SSP0->SR & BIT(4) )	// SPI0 busy
	;
return LPC_SSP0->DR;
}

 

Это писано под LPC1111, но модуль SSP у него точно такой же - тут просто коллега комментариев красиво понаписал :-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо большое за помощь! и за выложенный код. Нашел ошибку в своем, при инициализации SSP не так был сконфигурирован Pin, что и привело к ошибке. Не то значение в регистр, и CLK не работает, а соответственно и SPI. А надо было LPC_PINCON->PINSEL0 |= (0x2UL<<30); (вместо LPC_PINCON->PINSEL0 |= (0x3UL<<30);).

 

P.S. Смотрел на логическом анализаторе вместо USB приставки ))

Изменено пользователем cinema_effect

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...