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

MSP430 и I2C. Постоянно - UCBBUSY.

Добрый день. Есть микроконтроллер MSP40F5438 и не могу побороть проблему замкнутого цикла while( UCB1STAT & UCBBUSY ); Поиск показал, что я не одинок, и нашел информацию о том, что необходимо реализовывать I2C Bus Clear, из спецификации. Для этого написал простой цикл( здесь, и далее я использую UCB1, у которого PORT5.4 - SCL, PORT3.7 - SDA):

P5DIR |= BIT4;
P5SEL &= ~BIT4;
P5OUT &= ~BIT4;
for( pulseCounter = 0; pulseCounter < 9; pulseCounter++ ) {
P5OUT |= BIT4;
__delay_cycles( 100 );
P5OUT &= ~BIT4;
__delay_cycles( 100 );
}
P5OUT |= BIT4;
P5SEL |= BIT4;

 

После его выполнения, шина по прежнему остается занятой. Микроконтроллер работает на частоте 25МГц поэтому __delay_cycles( 100 ); дает задержку в 5мкс.

 

Как все таки правильно делать ресет шины? Единственное, что пока я нашел, что шина становится свободной, как только я переподключаю девайс с которым общаюсь. Протокол обмена с девайсом прост - изначально контроллер и девайс находятся в режиме в slave-receiver, а переключаются в master-transmitter только когда нужно что-то передать. После конфигурирования, мне необходимо инициализировать девайс, но это невозможно т.к шина занята.

Спасибо за любые идеи.

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


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

А до того как подключили девайс к шине, на шине какие уровни по напряжению?

И зря так делаете P5OUT |= BIT4;

Вы управляйте направлением порта а не его логикой. OUT = 0; а потом либо DIR |= BIT4; либо DIR &= ~BIT4;

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

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


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

Во-первых, вам правильно сделали замечание насчет управления лог.1 записью в P5OUT. Шина I2C управляется открытым коллектором или открытым стоком. Поэтому лог.1 нужно формировать, запрограммировав пин как вход, а не как выход с лог.1.

Во-вторых, в нормальном состоянии на шине I2C лог.1, а вы как-то странно заканчиваете цикл Bus clear выдавая лог.0 на SCL. Это неправильно. нужно освободить SCL, установив лог.1 в конце Bus clear.

В-третьих, Bus clear нужно выполнять до инициализации модуля I2C. Ну или после процедуры Bus clear (ре)инициализировать его вновь.

Ну и в-четвертых, "глупый" вопрос. У вас вообще pull-up резисторы на шине имеются?

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


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

А до того как подключили девайс к шине, на шине какие уровни по напряжению?

И зря так делаете P5OUT |= BIT4;

Вы управляйте направлением порта а не его логикой. OUT = 0; а потом либо DIR |= BIT4; либо DIR &= ~BIT4;

 

К сожалению уровни посмотреть не могу, пишут под собранную железку и никуда не добраться.

 

Во-первых, вам правильно сделали замечание насчет управления лог.1 записью в P5OUT. Шина I2C управляется открытым коллектором или открытым стоком. Поэтому лог.1 нужно формировать, запрограммировав пин как вход, а не как выход с лог.1.

Во-вторых, в нормальном состоянии на шине I2C лог.1, а вы как-то странно заканчиваете цикл Bus clear выдавая лог.0 на SCL. Это неправильно. нужно освободить SCL, установив лог.1 в конце Bus clear.

В-третьих, Bus clear нужно выполнять до инициализации модуля I2C. Ну или после процедуры Bus clear (ре)инициализировать его вновь.

Ну и в-четвертых, "глупый" вопрос. У вас вообще pull-up резисторы на шине имеются?

 

Pull-up резисторы есть. Т.е выходит, что цикл инициализации USCI в режим I2C начинать с UCB1STAT & UCBBUSY, и если вернет истину, то делать сброс, а потом конфигурировать? Я заметил дебаггером, что флаг UCBBUSY устанавливается уже после инициализации, а не до того. В этом случае делаем Bus clear, и после него инициализировать все заново?

 

Поправил Bus clear функцию:

void vI2CBusClear() {    
    char pulseCounter = 0;
    P5SEL &= ~BIT4;
    P5OUT &= ~BIT4;
    for( pulseCounter = 0; pulseCounter < 9; pulseCounter++ ) {
        P5DIR ^= BIT4;        
        __delay_cycles( 100 );
    }
    P5DIR &= ~BIT4;
    P5SEL |= BIT4;
}

 

Спасибо.

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

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


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

Во-первых, вам правильно сделали замечание насчет управления лог.1 записью в P5OUT. Шина I2C управляется открытым коллектором или открытым стоком. Поэтому лог.1 нужно формировать, запрограммировав пин как вход, а не как выход с лог.1.

Насчет этого не очень понятно. Если порт поставить на вход, то как тогда подавать импульсы?

 

П.С. Такая же проблема

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


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

регистр OUT = 0, как для вывода SCL так и для вывода SDA. На этих линиях должны быть резисторы подвешенные к 3 В, примерно 5-15 кОм. Что бы сделать логическую "1" на линии, нужно порт сделать входом, PxDIR &= ~BITx; что бы сделать логический "0" необходимо порт сделать выходом, PxDIR |= BITx;

А лучше использовать аппаратный I2C.

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


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

Я и так аппаратный использую. Но в msp340f47187, насколько я понимаю, нет аппаратного BusClear. Поэтому приходится перенастраивать порты (SEL = 0), а после давать импульсы. Или я где-то не прав...

И... насколько я понимаю, импульсы нужно подавать только на SCL? в спецификации написано:

 

... If the data line (SDA) is stuck LOW, the master should send nine !!clock pulses!!...

 

 

И, может быть, задаю глупый вопрос: объясните почему если порт настроен на вход, то будет лог 0, а если на выход, то будет лог 1?

 

И почему так делать лучше, чем через OUT = 0/1

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


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

Я же написал наоборот. Вход это 1, выход это 0.

Аппаратный я использовал во втором семействе. Никаких проблем не было.

Если Вы мастер, то и SCL и SDA дёргать надо, если нет то только SDA.

 

И почему так делать лучше, чем через OUT = 0/1

Когда у slave будет 0, а вы раз так и OUT = 1 сделаете, то получится КЗ по питанию. 3В на GND и скорее всего порты выгорят.

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

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


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

Что именно не понятно?

Пока вы отвечали, я редактировал своё предыдущее сообщение.

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


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

Ну допустим, почему если я мастер, нужно дергать обе линии, а не только SCL. Ведь в спецификации этого нет...

 

И вы говорите, что использовали аппаратный, и bus clear делать не приходилось? Если так, может у меня в программе не все гладко...

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

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


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

Обнаружил, что после выставления адреса и настройки i2c на передачу нужна задержка перед стартовым состоянием. Не могу понять почему?

 

Снимаю вопрос) Разобрался, дело было не в этом

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


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

На MSP430F5342 делаю BusClear так...

1. При инициализации портов настраиваю линию порта SCL в out, а SDA в in.

2. Делаю 10 тактов SCL в последовательности 1,0;1,0;... 1,0

3. Перевод SDA в out, уровень SDA=0.

4. Сигнал STOP - SCL=1 и после этого SDA=1

5. Перевод выводов под управление модуля USCI записью 1 в порт PSEL.

 

Все изменения уровней делаются с задержкой чтоб соблюсти скорость не выше 100кГц.

Работает такой BusClear у меня уверенно. Проц находится в непрерывном опросе трёх IIC устройств, сброс и снятие питания делается часто (откл. батареек, подключение к программатору и проч.) - шина I2C всё время доступна.

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


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

Есть ещё предположение, что иногда STOP в конце BusClear может не сработать - если подчинённое устройство выдаст в это время ACK на шину (если ведомый IIC был как Slave Transmitter).

Потому, для надёжности я добавил сегодня STOP ещё ДО 10 тактов на линии SCL, а линию SDA использую как открытый коллектор чтоб уменьшить энергопотребление.

 

В итоге всё выглядит так:

1. Бит Pout(SDA)=0 (для будущей имитации открытого коллектора на линии SDA с применением регистра Pdir).

2. Pdir(SCL)=1, Pout(SCL)=0.

3. Pdir(SDA)=1 на линиях SCL и SDA получился ноль - исходная позиция для STOP.

4. Pout(SCL)=1, Pdir(SDA)=0 провёл первый STOP на шине.

5. 10 тактов SCL в последовательности 1,0;1,0;... 1,0

6. Pdir(SDA)=1 на линиях SCL и SDA ноль - исходная позиция для второго STOP.

7. Pout(SCL)=1, Pdir(SDA)=0 провёл второй STOP на шине.

8. Перевод выводов под управление модуля USCI записью 1 в порт PSEL.

 

В таком виде BusClear наверное ещё надёжнее. Если первый STOP придётся на ACK подчинённого, то после 10 тактов на линии SCL, второй STOP попадёт уже в точку :rolleyes:

 

:excl: Вот ещё что... У меня все устройства I2C не запускают никаких действий по сигналу STOP, потому я применяю STOP для BusClear (а одно устройство даже требует STOP для завершения обмена - иначе оно за себя не ручается :biggrin: (барометр BMP085) ).

А если на шине I2C есть флешка - то лучше наверное ограничиться классическим BusClear из только из 9 тактов SCL...

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


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

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

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

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

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

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

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

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

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

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