Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: подскажите с работой SPI в MSP430F249
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
mzhelezkin
Здравствуйте. Нужно по SPI интерфейсу соединить контроллер MSP430F249 и вокодер CMX618. Программу пишу в IAR Embedded Work Bench for MSP430 v4.20.1. Для работы с SPI микроконтроллера пишу несколько функций:

Код
//******************************************************************************
// Инициализация SPI интерфейса
//******************************************************************************
void SPI_Setup(void)
{
  DCO_Init();                               // Инициализация генератора
  DIO_Init();                               // Инициализация портов ввода/вывода
  
  // Инициализация режима работы SPI
  UCB1CTL1 |= UCSWRST;
  UCB1CTL0 |= UCCKPL + UCMSB + UCMST + UCSYNC;  // 3-pin, 8-bit SPI master
  UCB1CTL1 |= UCSSEL_2;                     // SMCLK
  UCB1BR0 |= 0x02;                          // BRCLK = SMCLK/2
  UCB1BR1 = 0;                              //
  UCB1CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  UC1IE |= UCB1RXIE | UCB1TXIE;             // Enable USCI1 RX interrupt
  
  __bis_SR_register(LPM0_bits + GIE);       // CPU off, enable interrupts
  
  // задержка 15 мс
  __delay_cycles(15000);
}



Привожу функцию DCO_Init();

Код
//******************************************************************************
// DIO_INIT(): функция инициализации внутреннего генератора
//******************************************************************************
void DCO_Init(void)
{
  volatile unsigned int i;
  
  if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)                                    
  {  
    while(1);                               // If calibration constants erased
                                            // do not load, trap CPU!!
  }  
  BCSCTL1 = CALBC1_1MHZ;                    // Set DCO
  DCOCTL = CALDCO_1MHZ;
  for(i=2100;i>0;i--);                      // Wait for DCO to stabilize.

}


И еще одна функция, функция чтения значения регистра из вокодера

Код
//******************************************************************************
// SPI_ReadReg(): считывает 8-и битное значение из регистра с адрессом (addr).
// Полученное значениеэтого регистра записывается в переменную x
//******************************************************************************
char SPI_ReadReg_8(char addr)
{
  char x;                           // Переменная в которой хранится значение
                                    // регистра
  
  P5OUT &= ~CSN;                    // Выбор CMX618
  
  
  //делаем задержки примерно 3 мкс
  __no_operation();
  __no_operation();
  __no_operation();
  
  while (!(UC1IFG & UCB1TXIFG));    // Ждем пока TX буфер не освободиться
  UCB1TXBUF = addr;                 // Записываем в TX буфер адресс
  while (!(UC1IFG & UCB1TXIFG));    // Ждем пока TX буфер не освободиться
  UCB1TXBUF = 0;                    // Делаем ложную передачу, одновременно
                                    // принимаем значение из нужного регистра
  //while (!(UCB1STAT & UCBUSY));     // Ждем пока операция приема/передачи не
                                    // закончится
  while (!(UC1IFG & UCB1RXIFG));
  
  x = UCB1RXBUF;                    // Записываем в переменную x принятое
                                    // значение регистра
  
  P5OUT |= CSN;                     // Отключаем CMX618  
  
  return x;                         // Возвращаем x  
}


Теперь несколько вопросов:

1. Для примера сделал программу
Код
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Остановка сторожевого таймера

  static char value;                        
  
  SPI_Setup();

  value = SPI_ReadReg_8(MVCFG);
  
  while(1)
  {}
}


Программа зацикливается когда вызывается функция DCO_Init(), а именно на строчке
Код
for(i=2100;i>0;i--);                      // Wait for DCO to stabilize.

Получается что генератор не стабилизируется? (Эту настройку генератора я взял из примера, поэтому не пойму что она делает.)

2. Если я убираю строку
Код
__bis_SR_register(LPM0_bits + GIE);       // CPU off, enable interrupts

то программа не "подвисает" на цикле for. Но естественно не работае SPI. Так как прерывания отключены.

3. Объясните пожалуйста когда появляется сигнал тактирования на ножке CLK и смогу ли посмотреть его на осциллографе?. Сигнал появляется когда я дергаю CSN в ноль или когда записываю в буфер передатчика UCB1TXBUF данные?
rezident
Опять недопонимание. Если вы используете прерывания, то оформите функции обработки прерываний с соответствующими векторами. Если же работаете по опросу флагов (а это по тексту программы так и выходит), то не следует разрешать прерывания SPI. Флаги устанавливаются независимо от того, разрешены или запрещены прерывания от данного модуля.
Второе недопонимание. SPI интерфейс синхронный. Для того чтобы что-то принять нужно что-то передать. Т.е. тактовый сигнал на CLK появляется только на время передачи текущего байта. Сигнал STE в 3-х проводном режиме SPI не влияет на транзакцию. В 4-х проводном режиме сигнал STE используется для обеспечения работы "мультимастера". Вам это не нужно. Используйте любой вывод в режиме выхода как GPIO, чтобы программно управлять сигналом CSN для слейва.
Вообще же следует более внимательно читать User's Guide. И писать куски программы последовательно. После того, как станет понятным и нормально заработает предыдущий. Вот вы не понимаете зачем нужен цикл при инициализации тактирования. Ну дык прочитайте соответствующий раздел и осознайте - зачем?
mzhelezkin
Вас понял rolleyes.gif Спасибо за ответ, но теперь еще вопрос.

1. Не могу разобрать работает у меня SPI или нет. Дело в том что плату, на которой припаяны master (контроллер) и slave (CMX618), делали сами. Микросхема CMX618 очень сложна в пайке и не понятно припаяна она нормально или нет. Есть ли какой-нибудь способ проверить работает SPI или нет, даже если slave не подключен.

Я отключаю прерывания, инициализация проходит нормально, т.е. программа нигде не зацикливается, не останавливается. Как вы и сказали SPI настроен в 3-х выводный режим, а выбор ведомого (сигнал CSN) я делаю с помощью вывода P5.0
ih_
Цитата(mzhelezkin @ Dec 8 2010, 09:19) *
... Есть ли какой-нибудь способ проверить работает SPI или нет, даже если slave не подключен.
Если нет прибора для визульного контроля изменений напряжения на выводах, то попробуйте замкнуть выводы SOMI и SIMO. Сначала внутри, есть специальный бит (LISTEN), затем снаружи. Передайте, посмотрите, что принялось. Проверьте соответствие режима, те данные в slave записываются по фронту или спаду синхроимпульса, а так же значение его фазы.
Если прибор есть, можно зациклить код:
Код
while(1){
value = SPI_ReadReg_8(MVCFG);
__no_operation();
__no_operation();
__no_operation();
  };
И изучить работу модуля, на катринке "пачки" синхроимпульсов от передачи/приема байта, будут хорошо различимы.
mzhelezkin
Спасибо всем. SPI заработал, микросхемы соединились sm.gif Как было сказано, прерывания убрали. И немного изменил функцию char SPI_ReadReg_8(char addr)

Код
char SPI_ReadReg_8(char addr)
{
  char x;                           // Переменная в которой хранится значение
                                    // регистра UCB1RXBUF
  while (UCB1STAT & UCBUSY);        // Ждем пока операция приема/передачи не
                                    // закончится
  
  P5OUT &= ~CSN;                    // Выбор CMX618
  
  
  //делаем задержку примерно 1 мкс
  __no_operation();
  
  
  UCB1TXBUF = addr;                 // Записываем в TX буфер адресс регистра, из
                                    // из которого считываем данные
  while (!(UC1IFG & UCB1TXIFG));    // Ждем пока TX буфер не освободиться
  __no_operation();                 // Задержка 1 мкс, чтобы дать CMX618
                                    // переключиться на нужный адресс
  UCB1TXBUF = 0;                    // Делаем ложную передачу, одновременно
                                    // принимаем значение из нужного регистра  
  while (!(UC1IFG & UCB1RXIFG));  
  x = UCB1RXBUF;                    // Записываем в переменную x принятое
                                    // значение регистра
  while (UCB1STAT & UCBUSY);        // Ждем пока операция приема/передачи не
                                    // закончится
  
  P5OUT |= CSN;                     // Отключаем CMX618  
  
  return x;                         // Возвращаем x  
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.