Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Пример работы SPI в MSP430F149
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
_AlexMan_
Помогите плиз, мучаюсь с микрухой PGA2310, управляется по SPI, так вот ни одна реализация для MSP430F149 не работает у меня, пришлите код рабочего примера с инициализацией и тупо передачей байтов по SPI.
Пожайлуста очень надо!
korobov_michael
Инициализация

Код
//структуры для SPI
struct __TX
{
    char TXData[20];
    char CurrByte;
    char TotalToTX;
    char TXBusy;
};

struct __RX
{
    char RXData[20];
    char CurrByte;
    char TotalRXed;
};


void initSPI()
{
 P3SEL = 0x0E;
 P3DIR = 0x0A;
 U0CTL = SWRST + SYNC + CHAR + MM;
 U0TCTL |= SSEL1 + STC + CKPH /*+ CKPL*/;
 U0BR0 = 0x08;
 U0BR1 = 0x00;
 U0MCTL = 0x000;
 ME1 = USPIE0; 
 U0CTL &= ~SWRST;
 IE1 |= URXIE0;
}


Обработчик прерывания

Код
#pragma vector=USART0RX_VECTOR
__interrupt void SPI0_rx (void)
{
unsigned long spi_buf;
spi_buf = U0RXBUF;
RX.RXData[RX.CurrByte++] = (unsigned char)(spi_buf&0x00FF);
RX.TotalRXed = RX.CurrByte;
if ((++TX.CurrByte <= TX.TotalToTX)&&(TX.TXBusy))
{
U0TXBUF = TX.TXData[TX.CurrByte];
}
else
{
TX.TXBusy = 0;
TX.CurrByte = 0;
fDataTransfer = 0;
NSS_CONFIG(1);        //end SPI Transaction - CS - в "1"
}
}


Использование

Код
//setting NSS_Config Setting
void NSS_CONFIG(char SET)
{
 if(SET)
     P1OUT |= _BV(4);
 else
     P1OUT &= ~_BV(4);
}

void do_SPI1_start_TX()
{
 TX.TXBusy = 1;
 TX.CurrByte=0;
 RX.CurrByte=0;
 NSS_CONFIG(0);        //end SPI Transaction - CS - в "0"
 U0TXBUF = TX.TXData[TX.CurrByte];
 // TX.CurrByte++;
}

}
_AlexMan_
я немного видоизменил, практически ничего совсем, но сигнал попрежнему не передаеться. Точнее осциллографом не смотрел еще пока, но вот на выходе PGA3210 стабильный "0" при подаче на вход переменногг напряжения в 0,5 В 2кГц.
Может быть что нибудь посоветуете, например в схеме ключения? Понятно что надо осциллографом глянуть но пока не добраться мне до него, увы.
Вот что касаеться примера, то я сменил прирывание по приему на прерывание по передатчики, может быть это неверно совсем?, но подключаеться у меня только MOSI и UCLK., ну и еще CS.
rezident
Цитата(_AlexMan_ @ Jan 16 2009, 18:39) *
Может быть что нибудь посоветуете, например в схеме ключения?
А что можно посоветовать, если вы не показываете свою схему? Телепатию в форумчан тренируете?
Цитата(_AlexMan_ @ Jan 16 2009, 18:39) *
Вот что касаеться примера, то я сменил прирывание по приему на прерывание по передатчики, может быть это неверно совсем?, но подключаеться у меня только MOSI и UCLK., ну и еще CS.
Аналогично. Откуда мы знаем, что на что вы там поменяли и как используете SPI вообще и CS в частности? Схему и исходный код в студию!
mikesm
Можно вот так попробовать. Написать SPI вручную, на те же самые выводы, без использования прерываний, и прямым управлением выводов портов.
SPI в MSP430 работает своеобразно, и не факт, что заработает сходу, может где то тактового импульса не хватает для PGA2310.А написанный вручную легко проверить, что и как работает, и как PGA2310 на него реагирует. После того как запустите прием и передачу в ручном режиме,
потом можно один канал, например передачу сделать в автомате на SPI, а прием опять же вручную. И наконец оба направления в автомате.
_AlexMan_
Вот исходный текст

CODE
#define bitset(var,bitno) ((var) |= 1 << (bitno))
#define bitclr(var,bitno) ((var) &= ~(1 << (bitno)))

#define B1 BIT4&P4IN //B1 - P4.4

void initSPI();
void NSS_CONFIG(char SET);
void do_SPI1_start_TX();

//структуры для SPI
// структура передачи
typedef struct
{
char TXData[20];
char CurrByte;
char TotalToTX;
char TXBusy;
} __TX;

// структура приема
typedef struct
{
char RXData[20];
char CurrByte;
char TotalRXed;
} __RX;

__TX TX;
__RX RX;

#pragma vector=USART0TX_VECTOR
__interrupt void TxD()
{
if ((++TX.CurrByte < TX.TotalToTX)&&(TX.TXBusy))
{
U0TXBUF = TX.TXData[TX.CurrByte];// передача байтов из буффера
}
else
{
TX.TXBusy = 0;
TX.CurrByte = 0;
NSS_CONFIG(1); //end SPI Transaction - CS - в "1"
}
}

void initSPI()
{
P3SEL = 0x0E;
P3DIR = 0x0A;
U0CTL = SWRST + SYNC + CHAR + MM;
U0TCTL |= SSEL1 + STC + CKPH /*+ CKPL*/;
U0BR0 = 0x08;
U0BR1 = 0x00;
U0MCTL = 0x000;
ME1 = USPIE0;
U0CTL &= ~SWRST;
IE1 |= UTXIE0;
}

//setting NSS_Config Setting
void NSS_CONFIG(char SET)
{
if(SET)
bitset(P6OUT,7);
else
bitclr(P6OUT,7);
}

void do_SPI1_start_TX()
{
TX.TXBusy = 1;
TX.CurrByte=0;
RX.CurrByte=0;
NSS_CONFIG(0); //start SPI Transaction - CS - в "0"
U0TXBUF = TX.TXData[TX.CurrByte];
}

void main(void)
{
int flag = 0;
P6DIR |= 0x80;
bitset(P6OUT,7);
TX.TotalToTX = 2;
TX.TXData[0] = 0x2d; // просто для примера
TX.TXData[1] = 0x7d;
initSPI();
while(1)
{
if (((B1) == 0)&&(flag == 0)) //B1 is pressed
{
flag = 1;
do_SPI1_start_TX();
}
}
}

, все вроде предельно просто, но не работает wacko.gif

Вот используемая схема соединений
Нажмите для просмотра прикрепленного файла
rezident
Цитата(_AlexMan_ @ Jan 17 2009, 02:44) *
все вроде предельно просто, но не работает wacko.gif
У вас вообще не вызываются прерывания потому, что не установлен глобальный флаг разрешения прерываний GIE.
Все остальное внимательно не анализировал.
korobov_michael
Цитата(_AlexMan_ @ Jan 16 2009, 15:39) *
я сменил прирывание по приему на прерывание по передатчики


Во-первых, как и говорил rezident, установите глобальные прерывания (__enable_interrupt()), кроме того, у SPI принцип работы заключается в том, что передача байта от мастера одновременно означает прием байта от Slave. Поэтому вектор прерывания можно было не менять. Ну и, в довершение, хотя на данный момент это не актуально, в while() проверять кнопку так, как Вы это делаете, мягко говоря, нехорошо. Контроллер за очень маленькое время напередает кучу данных по SPI. Такую работу хорошо делать по таймеру. И обычно надо сделать антидребезг.
korobov_michael
Цитата(_AlexMan_ @ Jan 16 2009, 23:44) *
#pragma vector=USART0TX_VECTOR
__interrupt void TxD()
{

...


}

[/code]
все вроде предельно просто, но не работает wacko.gif


Там есть еще одна тонкость. Преывание USART0TX_VECTOR в MSP430 работает по освобождению буфера, а не по фактической передаче байта. Это позволяет, в числе прочего, не делать задержек при передаче массивов – сразу после стоп-бита идет старт бит следующего байта. Но если буфер освободился, то это означает лишь, что можно класть в буфер следующий байт, а не то, что произошел обмен байтами. Поэтому использовать надо именно как я показывал - USART0RX_VECTOR.


Стормозил - это надо было сразу заметить
_AlexMan_
Исправил все замечания, за них спасибо. Все таки посмотрел осциллографом, тактирующие импульсы не идут, но если в режиме отладке прогонять то в обработчик прерывания по приему заходит, но при этом я ничего не подключаю на вход MISO! Проверил бит LISTEN там 0. А сама PGA молчит как и прежде.
Может кто нибудь подсобит с программной реализацией SPI, хотелось бы тогда уж и с ней попытать счастья smile3046.gif
korobov_michael
Цитата(_AlexMan_ @ Jan 20 2009, 17:55) *
Все таки посмотрел осциллографом, тактирующие импульсы не идут

На всякий случай - осциллограф аналоговый или цифровой? Все-таки эти тактирующие импульсы идут всего-лишь за время 16/fтакт (при двух передаваемых байтах) – единицы микросекунд – и не углядишь
_AlexMan_
аналоговый, но при развертки 1мкс должно же что то происходить на экране, а не просто отображаться на тактирующем выходе стабильно 0, а на MOSI почему то стабильно 1. А тактирующие импульсы идут всегда как только произошла инициализация SPI или только непосредственно при передачи данных?
rezident
Цитата(_AlexMan_ @ Jan 21 2009, 13:15) *
А тактирующие импульсы идут всегда как только произошла инициализация SPI или только непосредственно при передачи данных?
Конечно же только при обмене данными. Причем именно при обмене. Для того чтобы что-то прочитать по SPI, нужно обязательно что-либо передать.
korobov_michael
Так, на всякий случай. Посмотри, пожалуйста, с каким именно USART ты работаешь - там их два, и, может быть, просто не тот настроили и не с тем работаем. Код, который я приводил, предназначен для USART0. Это первая проверка. Во-вторых, попробуй такой код. 

Код
</P><P>void main(void)
{
 P6DIR |= 0x80;
 bitset(P6OUT,7);
 initSPI();
 //прерывания не разрешаем!!! 
 //все делаем по флагу
 while(1)
 {
     //для проверки линию CS не дергаем - 
     //пусть слейв не мучается
     U0TXBUF = 'A';
     while (!(IFG1 & UTXIFG0));
 }
}


</P><P>


Он все время передает байты и в таком режиме ты точно увидишь, идет что-то или нет на линии SCLK. Кстати, проверишь сразу линию MOSI. 
_AlexMan_
Нет уарт то точно тот, было бы обидно в этом ошибиться). Я посмотрел цифровым осциллографом вариант без обработки прерываний: данные передаються и тактирующие импульсы тоже имеются, проблема во времени установки и снятия сигнала CS. вот сейчас сигнал снимаеться раньше чем осуществляется передача второго байта коэфициэнтов. И выставляется намного раньше подачи первого тактирующего импульса. Какими должны быть данные временные интервалы между фронтами CS и тактирующими импульсами?
rezident
Цитата(_AlexMan_ @ Jan 23 2009, 02:25) *
Какими должны быть данные временные интервалы между фронтами CS и тактирующими импульсами?
Странные вопросы. В даташите же все написано! 90нс и 35нс соответственно.
Алгоритм записи 16 бит должен быть такой.
1. Устанавливаем активный уровень CS.
2. если буфер готов, то "пихаем" первый байт в буфер передатчика SPI.
3. ждем готовности буфера передатчика SPI
4. если буфер готов, то "пихаем" второй байт в буфер передатчика SPI и очищаем флаг готовности буфера приемника SPI
5. ждем установки флага готовности приемника SPI.
6. сбрасываем активный уровень CS
Если используются прерывания, то работаем по прерываниям от приемника SPI. После активации CS первый байт записываем в буфер передатчика SPI. Второй же байт записываем в буфер передатчика уже в прерывании от приемника SPI. После второго попадания в прерывание от приемника SPI сбрасываем активный уровень CS, но в передатчик ничего уже не пишем.
Сергей Борщ
Цитата(rezident @ Jan 23 2009, 00:30) *
Алгоритм записи 16 бит должен быть такой.
Несколько вопросов по вашему алгоритму:

1) Как буфер может быть не готов на шаге 2? Мы что, CS дергали во время передачи чего-то предыдущего? Тогда ведомый принял мусор. Мне кажется, эти два шага надо поменять местами. Хотя мусор из ведомого будет вытеснен следующими 16 битами, так что может и не страшно.

2) если на шаге 4 между пиханием байта и очисткой флага произойдет прерывание - данные успеют уйти, мы затрем нужный флаг и на шаге 5 повиснем навечно. Сдается, очистку флага и запихивание в буфер тоже надо поменять местами.
rezident
Цитата(Сергей Борщ @ Jan 25 2009, 00:08) *
1) Как буфер может быть не готов на шаге 2?
CS дергается программно и я заранее не знаю, может он только что предыдущую запись окончил. А если вдруг тактирование SPI от часового кварца? smile.gif Конечно же тогда буфер будет не готов. В общем проверка вовсе не лишняя.
Цитата(Сергей Борщ @ Jan 25 2009, 00:08) *
2) если на шаге 4 между пиханием байта и очисткой флага произойдет прерывание - данные успеют уйти, мы затрем нужный флаг и на шаге 5 повиснем навечно. Сдается, очистку флага и запихивание в буфер тоже надо поменять местами.
Отнюдь! Это может случиться лишь в том случае, если частота тактирования модуля USART по крайней мере в 8 раз выше MCLK. Очистка флага занимает 5 тактов MCLK, а передача байта не менее 16 тактов, если модуль SPI тактируется такой же частотой (макс. частота тактирования в режиме SPI UCLK/2). Если же будет соотношение частот другое, то мы можем нарваться на тот факт, что мы очистим флаг готовности приемика, но он будет установлен после приема первого байта. А нас-то интересует флаг готовности именно после приема второго байта! Кстати, ты не забыл что в MSP430 SPI 8-ми битный, а не произвольной разрядности как в LPC2000? wink.gif
В общем я бы наверное предпочел использовать прерывания. Там все более определенно. Возникло прерывание от приемника - значит очередная транзакция завершена.
Сергей Борщ
Цитата(rezident @ Jan 24 2009, 22:19) *
CS дергается программно и я заранее не знаю, может он только что предыдущую запись окончил. А если вдруг тактирование SPI от часового кварца? smile.gif Конечно же тогда буфер будет не готов. В общем проверка вовсе не лишняя.
Недопонял. Если буфер не готов - идет передача. А мы в это время дергаем CS. Ведомый начнет принимать мусор. Почему просто не ждать готовности до дерганья CS?
Цитата(rezident @ Jan 24 2009, 22:19) *
Отнюдь! Это может случиться лишь в том случае, если частота тактирования модуля USART по крайней мере в 8 раз выше MCLK. Очистка флага занимает 5 тактов MCLK, а передача байта не менее 16 тактов,
Между отгрузкой байта в буфер и очисткой флага может быть вызван обработчик прерывания, который может длиться гораздо дольше передачи байта. Выходит, чистить флаг надо перед каждой передачей, и ждать его после каждой передачи. Да, прелести двойного буферирования не используются, но альтернатива - только запрещать прерывания.
Цитата(rezident @ Jan 24 2009, 22:19) *
Если же будет соотношение частот другое, то мы можем нарваться на тот факт, что мы очистим флаг готовности приемика, но он будет установлен после приема первого байта. А нас-то интересует флаг готовности именно после приема второго байта!
О!
Цитата(rezident @ Jan 24 2009, 22:19) *
Кстати, ты не забыл что в MSP430 SPI 8-ми битный, а не произвольной разрядности как в LPC2000? wink.gif
Нет, не забыл. А вот с LPC - по принципу "пустил-забыл". Написал года два назад кусок, он работает и что там творится - уже не помню.
Цитата(rezident @ Jan 24 2009, 22:19) *
В общем я бы наверное предпочел использовать прерывания. Там все более определенно. Возникло прерывание от приемника - значит очередная транзакция завершена.
Тот же фиг - анализируется каждое срабатывание.


Есть альтернатива - если скорость передачи достаточно высока по сравнению с ядром, то флаг можно вообще не анализировать, а просто вставить нужное количество nop-ов после записи. На высоких скоростях это будет даже эффективнее, учитывая накладные на вход в прерывание и выход из него. При максимальной скорости SPI и ядра, учитывая еще время на подготовку очередных данных к отправке, там может получиться всего два-три nop-а. Я так делал на меге, 4 nop-а были выгоднее и по скорости и по размеру кода.
Kurt
пример работы с SPI. тактирование от внешнего кварца без использования прерываний
http://kurt.embedders.org/wiki/sources:spi0
может быть, поможет.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.