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

Проблема с I2C в MSP430F2617

Пришлось по необходимости заняться МК MSP430F2617. К счастью, для чайников в среде IAR есть примеры. Все примеры удалось запустить и отработать, кроме примера по I2C, хотя он там нужен. Привожу код в примере

#include "msp430x26x.h"

 

unsigned char TXData;

unsigned char TXByteCtr;

 

void main(void)

{

WDTCTL = WDTPW + WDTHOLD; // Stop WDT

P3SEL |= 0x06; // Assign I2C pins to USCI_B0

UCB0CTL1 |= UCSWRST; // Enable SW reset

UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode

UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset

UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz

UCB0BR1 = 0;

UCB0I2CSA = 0x48; // Slave Address is 048h

UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation

IE2 |= UCB0TXIE; // Enable TX interrupt

 

TXData = 0x01; // Holds TX data

 

while (1)

{

TXByteCtr = 1; // Load TX byte counter

while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent

UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition

__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts

// Remain in LPM0 until all data

// is TX'd

TXData++; // Increment data byte

}

}

 

//------------------------------------------------------------------------------

// The USCIAB0TX_ISR is structured such that it can be used to transmit any

// number of bytes by pre-loading TXByteCtr with the byte count.

//------------------------------------------------------------------------------

#pragma vector = USCIAB0TX_VECTOR

__interrupt void USCIAB0TX_ISR(void)

{

if (TXByteCtr) // Check TX byte counter

{

UCB0TXBUF = TXData; // Load TX buffer

TXByteCtr--; // Decrement TX byte counter

}

else

{

UCB0CTL1 |= UCTXSTP; // I2C stop condition

IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag

__bic_SR_register_on_exit(CPUOFF); // Exit LPM0

}

}

 

В комментарии указано: "Этот демо связывает два MSP430 по шине I2C. Мaster передает slave. Это код для master. Он постоянно передает 00h, 01h, ..., 0ffh и демонстрирует, как подключить I2C master transmitter для передачи одного байта using прерывание USCI_B0 TX." Так вот, я запустил этот пример, и он НЕ работает так, как написано в комментарии. В чем может быть дело?

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


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

Во-первых, нужно напомнить, что шина I2C обязательно требует pull-up резисторов на обеих линиях (SCL и SDA).

Во-вторых, этот пример слишком упрощен. Автомат состояний шины I2C гораздо сложнее и в идеале его нужно реализовывать полностью (назначить действие для каждого возможного варианта состояния шины).

В-третьих, нужно обязательно реализовать функцию Bus clear, описанную в спецификации I2C, вызываемую по тайм-ауту неактивности занятой шины. С такой необходимостью мы сталкивались неоднократно и поэтому реализуем ее всегда. Как минимум один раз, после подачи питания на устройства, подключенные к шине I2C, функцию Bus clear необходимо вызывать всегда.

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


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

Во-первых, нужно напомнить, что шина I2C обязательно требует pull-up резисторов на обеих линиях (SCL и SDA).

Во-вторых, этот пример слишком упрощен. Автомат состояний шины I2C гораздо сложнее и в идеале его нужно реализовывать полностью (назначить действие для каждого возможного варианта состояния шины).

В-третьих, нужно обязательно реализовать функцию Bus clear, описанную в спецификации I2C, вызываемую по тайм-ауту неактивности занятой шины. С такой необходимостью мы сталкивались неоднократно и поэтому реализуем ее всегда. Как минимум один раз, после подачи питания на устройства, подключенные к шине I2C, функцию Bus clear необходимо вызывать всегда.

 

Может, он и упрощен, но делать то, что указано в комментарии, он обязан (я так полагал). Но он вообще заходит в прерывание один раз, а потом "уходит в подполье", откуда его отладчиком IAR не вытащить. А эта функция BUS CLEAR, она описана в спецификации?

 

Очевидно, имеются в виду внешние - на плате - резисторы, подтягивающие провода SCK и SDA к напряжению питания, то есть к "1"?

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


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

Может, он и упрощен, но делать то, что указано в комментарии, он обязан (я так полагал). Но он вообще заходит в прерывание один раз, а потом "уходит в подполье", откуда его отладчиком IAR не вытащить.
Поясните более понятно, что именно не работает? Активности на шине I2C никакой нету? Или дебаггер не работает? Если только второе, то уберите из программы все команды перехода в режим энергосбережения. То бишь команду

__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts

замените на

__bis_SR_register(GIE); // Enable interrupts

А эта функция BUS CLEAR, она описана в спецификации?
Да, конечно же. Раздел 3.16 Bus clear. Для выведения зависшего слейва из "ступора" и разблокирования шины SDA необходимо, не создавая старт- или стоп-условий, сгенерировать на шине SCL не менее 9 тактовых импульсов. Для этого в MSP430 удобнее перепрограммировать пин к которому подключена SCL как GPIO в режиме вывода и выдать последовательность из 9 тактовых импульсов частотой не выше 400кГц или 100кГц (в зависимости от типа подключенных устройств). После этого можно перевести пин обратно на функцию SCL и начать новую передачу.

Очевидно, имеются в виду внешние - на плате - резисторы, подтягивающие провода SCK и SDA к напряжению питания, то есть к "1"?
Да, внешние. Внутренние pull-up не позволяют работать на высокой скорости.

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


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

Гм, все оказалось донельзя тривиально. Как только прицепили к SCK и SDA подтягивающие резисторы, обмен пошел. Есть, правда, некоторые шероховатости, но это уже отдельная тема. Спасибо за подсказку и дополнительные советы. Обязательно учтем.

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


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

Гм, все оказалось донельзя тривиально. Как только прицепили к SCK и SDA подтягивающие резисторы, обмен пошел. Есть, правда, некоторые шероховатости, но это уже отдельная тема. Спасибо за подсказку и дополнительные советы. Обязательно учтем.

Слова "обмен пошел" не совсем точно отражают состояние дел. Пошщел в одну сторону - master->slave. Может быть, я спрашиваю, как истинный чайник, очевидные вещи, но тем не менее спрошу: как выдать на GPIO последовательность тактовых импульсов с определенной частотой (например, 400 кГц) - это все для BusClear.

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

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


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

А 100кГц не устроит? :)

#define PIN_SCL (1U<<2)

P3OUT &= PIN_SCL^0xFF;
P3DIR &= PIN_SCL^0xFF;
P3SEL &= PIN_SCL^0xFF;
for (unsigned int cntr=0; cntr<9; cntr++)
{ P3DIR |= PIN_SCL;
  __delay_us(5);
  P3DIR &= PIN_SCL^0xFF;
  __delay_us(5);
}
P3SEL |= PIN_SCL;
P3OUT |= PIN_SCL;

 

Функцию задержки на 5 мкс __delay_us(5) сами уж как-нибудь определите. Хотя бы требуемым количеством NOPов.

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


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

Спасибо за код, должен сказать, что ничего военного в нем нет, и все достаточно прозрачно.

Впрочем, из примеров я сделал несколько выводов.

Во-первых, получается, что сам обмен включает, кроме передаваемых байтов, еще много чего (очевидно, все это организует встроенный в микроконтроллер модуль, реализующий скрытые функции I2C).

Например, в примерах (и, надо полагать, в реальных программах) нет передачи адреса - в лучшем случае он указывается в специальных регистрах при настройках протокола. А кто его тогда передает?

Нет там и "обрамления" передаваемых байтов (например, в адресной посылке, кроме самого 7-битного адреса, должен быть так называемый R/W бит, определяющий направление потока данных, а в обычной посылке 8 бит данных дополняются битом подтверждения). Их тоже наверняка формирует встроенный модуль.

Здесь для меня из примеров теперь непонятно следующее: я там нигде не нашел и намека на определение направления потока данных (то есть каким образом будет формироваться этот самый R/W бит). А это может быть определяющим для программирования обмена.

Например, в процессе работы с каким-либо устройством нужно запросить состояние определенного регистра. Для этого нужно послать запрос (ПЕРЕДАЧА) и перейти на прием. Это как-то нужно сделать программно.

Вот такие вопросы.

 

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


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

Вот такие вопросы.
Как говориться в таких случаях RTFM! :) Ответы на все эти вопросы есть в MSP430x2xx Family User's Guide (Rev. E), чтением которого вы видимо пренебрегли? Если у вас проблемы с английским, то купите книжку-перевод этого руководства. В соседней теме ее рекламировали.

 

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


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

Как говориться в таких случаях RTFM! :) Ответы на все эти вопросы есть в MSP430x2xx Family User's Guide (Rev. E), чтением которого вы видимо пренебрегли? Если у вас проблемы с английским, то купите книжку-перевод этого руководства. В соседней теме ее рекламировали.

 

Да нет, и с английским проблем у меня нет, и упомянутый вами документ имеется, я его вообще-то читал.

Впрочем, виноват, видимо, читал невнимательно. Сейчас прошелся по разделу I2C и таки нашел фразу RESTART, которой, очевидно, Master и должен менять направление потока данных.

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


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

Извините, что столь неугомонен, но с обменом по протоколу I2C все-таки не все ладно. У меня возникло подозрение, что slave (а в качестве такового в обмене участвует акселерометр LIS331DLH) не отвечает, не дает подтверждение, необходимое по протоколу. Судя по примерам, вся последовательность обмена:

Start - Slave Address - R/W - ACK - Data - ACK - S Slave Address - R/W - ACK - Data - ACK - Stop

недоступна для программы - значит, существует "нижний" уровень типа микропрограммного, реализцющий собственно обмен. Об этом, кстати, свидетельствует и то, что в упомянутой Вами книге есть раздел "Universal Serial Interface", и регистры этого раздела (например, USICTLx или USICNT etc), однако из программы ни один из этих регистров недоступен, хотя в самой книге есть Ассемблерные примеры управления через эти регистры.

Как все-таки убедиться, что подтверждение со стороны приемника slave действительно приходит (или НЕ приходит)? Ведь в последнем случае обмена как раз и не будет.

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


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

Об этом, кстати, свидетельствует и то, что в упомянутой Вами книге есть раздел "Universal Serial Interface", и регистры этого раздела (например, USICTLx или USICNT etc), однако из программы ни один из этих регистров недоступен, хотя в самой книге есть Ассемблерные примеры управления через эти регистры.

Уважаемый, если предположить, что у вас плохое зрение, то вы видимо забыли надеть очки? :cranky: Ну причем тут модуль USI (Universal Serial Interface) и соответствующий ему раздел в User's manual (Chapter 14), если в вашем кристалле модуль USCI (Universal Serial Communication Interface) и читать вам следует раздел Chapter 17. Universal Serial Communication Interface, I2C Mode? :laughing:

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


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

Уважаемый, если предположить, что у вас плохое зрение, то вы видимо забыли надеть очки? :cranky: Ну причем тут модуль USI (Universal Serial Interface) и соответствующий ему раздел в User's manual (Chapter 14), если в вашем кристалле модуль USCI (Universal Serial Communication Interface) и читать вам следует раздел Chapter 17. Universal Serial Communication Interface, I2C Mode? :laughing:

 

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

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


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

Как из программы отловить наличие подтверждения от приемника? Опять же никаких упоминаний (битов в регистрах) нет.
Опять ловлю вас на невнимательном чтении документации.

If the slave does not acknowledge the transmitted data the not-acknowledge interrupt flag UCNACKIFG is set. The master must react with either a STOP condition or a repeated START condition. If data was already written into UCBxTXBUF it will be discarded. If this data should be transmitted after a repeated START it must be written into UCBxTXBUF again. Any set UCTXSTT is discarded, too. To trigger a repeated start UCTXSTT needs to be set again.

post-3882-1286548083_thumb.png

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


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

Разработчики USART MSP430 2xx заложили в него 2 идеи, в общем-то спорные, но имеющие право на жизнь, без понимания которых вы не сможете понять все остальное:

(речь о режиме Master Transmitter/Receiver)

 

1 адрес Slave не является частью пакета данных, а задается отдельно. Это сильно упрощает программирование, если у Вас на шине одно устройство (частая ситуация). Вы один раз задаете адрес и можете забыть о нем, USCI сам вставляет его в начале каждого приема/передачи. Бит R/W при этом определяется битом UCTR.

 

2 Штатным ответом Slave является ACK, NACK - признак нештатной ситуации. По ACKу не выставляется никаких специальных флагов, просто контроллер дает знать о готовности к приему/передаче следующего байта через UCxxRXIFG/UCxxTXIFG, в случае получения NACK контроллер выставит UCNACKIFG ( вызовет прерывание), сотрет данные из передающего буфера, если они там есть, и будет ждать вашей реакции.

 

В общем, проще прислать код, наверное...

Вот кусок кода, только он для UCB1, надо будет подправить. Прерывания для приема,передачи не используются, NACK обрабатывается в ISR

Реализует как раз ваше:

Start - Slave Address - R/W - ACK - Data - ACK - S Slave Address - R/W - ACK - Data - ACK - Stop

 

void I2C_SetSlave(unsigned char slave_address, unsigned char baudrate)
{
  UCB1CTL1 |= UCSWRST;                       // Clear SW reset, resume operation
   UCB1CTL1 = UCSSEL_2 + UCSWRST;    // Use SMCLK, SW reset
  UCB1BR0 = baudrate;                          // set prescaler
  UCB1BR1 = 0;
  UCB1I2CSA = slave_address;                  // Set slave address
  UC1IFG &= ~(UCB1TXIFG+UCB1RXIFG);

  UCB1CTL1 &= ~UCSWRST;                       // Clear SW reset, resume operation
  if(UCB1STAT & UCBBUSY) I2C_BusReset();
}

unsigned char  I2C_ReadByteRs(unsigned char reg)
{
  UCB1CTL1 |= (UCTR + UCTXSTT);    // Master TX, start condition

  while (!(UC1IFG & UCB1TXIFG));      // Wait for address transmit
  UC1IFG &= ~UCB1TXIFG;
  UCB1TXBUF = reg;
  while (!(UC1IFG & UCB1TXIFG));      // Wait for register tx
  UC1IFG &= ~UCB1TXIFG;
  UCB1CTL1 &= ~UCTR;                    // Set master receiver mode
  UCB1CTL1 |= UCTXSTT;                  // Set start condition, Master rx
  while (UCB1CTL1 & UCTXSTT);         // Start condition sent?
  UCB1CTL1 |= UCTXSTP;                  // Set stop immediately
  while (!(UC1IFG & UCB1RXIFG));      // Wait for receive
   UC1IFG &= ~UCB1RXIFG;

  return UCB1RXBUF;
}


#pragma vector = USCIAB1RX_VECTOR
void USCIAB1RX_ISR(void)
{
   if (UCB1STAT & UCNACKIFG){                  // if slave sends NACK
    UCB1CTL1 |= UCTXSTP;                          // set STOP condition
    UCB1STAT &= ~UCNACKIFG;
    UC1IFG &= ~(UCB1TXIFG+UCB1RXIFG);
    // Здесь сообщить об ошибке
  }
}

И еще. Частая ошибка при работе с акселерометрами - забывают их инициализировать и сразу кидаются читать регистры осей. А многие акселерометры при включении уходят в сон и при чтении большинства регистров выдают нули.

 

2 rezident

Согласитесть, "TFM", который надо читать, в части I2C довольно мутный, точнее, слишком много впихнуто в крайне сжатом виде, рисунки - это вообще песня, учитывая, что легенда к ним приводится один раз и за 3 страницы до первого рисунка. Кстати, давно хотел спросить у Вас: учитывая Ваш опыт работы с MSP430, не кажется ли Вам, что I2C в 2хх намного глючнее, чем в 1хх?

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

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


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

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

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

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

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

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

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

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

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

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