Lemist 0 6 октября, 2010 Опубликовано 6 октября, 2010 · Жалоба Пришлось по необходимости заняться МК 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." Так вот, я запустил этот пример, и он НЕ работает так, как написано в комментарии. В чем может быть дело? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 6 октября, 2010 Опубликовано 6 октября, 2010 · Жалоба Во-первых, нужно напомнить, что шина I2C обязательно требует pull-up резисторов на обеих линиях (SCL и SDA). Во-вторых, этот пример слишком упрощен. Автомат состояний шины I2C гораздо сложнее и в идеале его нужно реализовывать полностью (назначить действие для каждого возможного варианта состояния шины). В-третьих, нужно обязательно реализовать функцию Bus clear, описанную в спецификации I2C, вызываемую по тайм-ауту неактивности занятой шины. С такой необходимостью мы сталкивались неоднократно и поэтому реализуем ее всегда. Как минимум один раз, после подачи питания на устройства, подключенные к шине I2C, функцию Bus clear необходимо вызывать всегда. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lemist 0 6 октября, 2010 Опубликовано 6 октября, 2010 · Жалоба Во-первых, нужно напомнить, что шина I2C обязательно требует pull-up резисторов на обеих линиях (SCL и SDA). Во-вторых, этот пример слишком упрощен. Автомат состояний шины I2C гораздо сложнее и в идеале его нужно реализовывать полностью (назначить действие для каждого возможного варианта состояния шины). В-третьих, нужно обязательно реализовать функцию Bus clear, описанную в спецификации I2C, вызываемую по тайм-ауту неактивности занятой шины. С такой необходимостью мы сталкивались неоднократно и поэтому реализуем ее всегда. Как минимум один раз, после подачи питания на устройства, подключенные к шине I2C, функцию Bus clear необходимо вызывать всегда. Может, он и упрощен, но делать то, что указано в комментарии, он обязан (я так полагал). Но он вообще заходит в прерывание один раз, а потом "уходит в подполье", откуда его отладчиком IAR не вытащить. А эта функция BUS CLEAR, она описана в спецификации? Очевидно, имеются в виду внешние - на плате - резисторы, подтягивающие провода SCK и SDA к напряжению питания, то есть к "1"? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 6 октября, 2010 Опубликовано 6 октября, 2010 · Жалоба Может, он и упрощен, но делать то, что указано в комментарии, он обязан (я так полагал). Но он вообще заходит в прерывание один раз, а потом "уходит в подполье", откуда его отладчиком 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 не позволяют работать на высокой скорости. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lemist 0 6 октября, 2010 Опубликовано 6 октября, 2010 · Жалоба Гм, все оказалось донельзя тривиально. Как только прицепили к SCK и SDA подтягивающие резисторы, обмен пошел. Есть, правда, некоторые шероховатости, но это уже отдельная тема. Спасибо за подсказку и дополнительные советы. Обязательно учтем. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lemist 0 7 октября, 2010 Опубликовано 7 октября, 2010 (изменено) · Жалоба Гм, все оказалось донельзя тривиально. Как только прицепили к SCK и SDA подтягивающие резисторы, обмен пошел. Есть, правда, некоторые шероховатости, но это уже отдельная тема. Спасибо за подсказку и дополнительные советы. Обязательно учтем. Слова "обмен пошел" не совсем точно отражают состояние дел. Пошщел в одну сторону - master->slave. Может быть, я спрашиваю, как истинный чайник, очевидные вещи, но тем не менее спрошу: как выдать на GPIO последовательность тактовых импульсов с определенной частотой (например, 400 кГц) - это все для BusClear. Изменено 7 октября, 2010 пользователем Lemist Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 7 октября, 2010 Опубликовано 7 октября, 2010 · Жалоба А 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ов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lemist 0 7 октября, 2010 Опубликовано 7 октября, 2010 · Жалоба Спасибо за код, должен сказать, что ничего военного в нем нет, и все достаточно прозрачно. Впрочем, из примеров я сделал несколько выводов. Во-первых, получается, что сам обмен включает, кроме передаваемых байтов, еще много чего (очевидно, все это организует встроенный в микроконтроллер модуль, реализующий скрытые функции I2C). Например, в примерах (и, надо полагать, в реальных программах) нет передачи адреса - в лучшем случае он указывается в специальных регистрах при настройках протокола. А кто его тогда передает? Нет там и "обрамления" передаваемых байтов (например, в адресной посылке, кроме самого 7-битного адреса, должен быть так называемый R/W бит, определяющий направление потока данных, а в обычной посылке 8 бит данных дополняются битом подтверждения). Их тоже наверняка формирует встроенный модуль. Здесь для меня из примеров теперь непонятно следующее: я там нигде не нашел и намека на определение направления потока данных (то есть каким образом будет формироваться этот самый R/W бит). А это может быть определяющим для программирования обмена. Например, в процессе работы с каким-либо устройством нужно запросить состояние определенного регистра. Для этого нужно послать запрос (ПЕРЕДАЧА) и перейти на прием. Это как-то нужно сделать программно. Вот такие вопросы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 7 октября, 2010 Опубликовано 7 октября, 2010 · Жалоба Вот такие вопросы.Как говориться в таких случаях RTFM! :) Ответы на все эти вопросы есть в MSP430x2xx Family User's Guide (Rev. E), чтением которого вы видимо пренебрегли? Если у вас проблемы с английским, то купите книжку-перевод этого руководства. В соседней теме ее рекламировали. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lemist 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Как говориться в таких случаях RTFM! :) Ответы на все эти вопросы есть в MSP430x2xx Family User's Guide (Rev. E), чтением которого вы видимо пренебрегли? Если у вас проблемы с английским, то купите книжку-перевод этого руководства. В соседней теме ее рекламировали. Да нет, и с английским проблем у меня нет, и упомянутый вами документ имеется, я его вообще-то читал. Впрочем, виноват, видимо, читал невнимательно. Сейчас прошелся по разделу I2C и таки нашел фразу RESTART, которой, очевидно, Master и должен менять направление потока данных. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lemist 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Извините, что столь неугомонен, но с обменом по протоколу 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 действительно приходит (или НЕ приходит)? Ведь в последнем случае обмена как раз и не будет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Об этом, кстати, свидетельствует и то, что в упомянутой Вами книге есть раздел "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: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Lemist 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Уважаемый, если предположить, что у вас плохое зрение, то вы видимо забыли надеть очки? :cranky: Ну причем тут модуль USI (Universal Serial Interface) и соответствующий ему раздел в User's manual (Chapter 14), если в вашем кристалле модуль USCI (Universal Serial Communication Interface) и читать вам следует раздел Chapter 17. Universal Serial Communication Interface, I2C Mode? :laughing: Может, я и не о том говорил, но вопрос все равно остается. Как из программы отловить наличие подтверждения от приемника? Опять же никаких упоминаний (битов в регистрах) нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 8 октября, 2010 Опубликовано 8 октября, 2010 · Жалоба Как из программы отловить наличие подтверждения от приемника? Опять же никаких упоминаний (битов в регистрах) нет.Опять ловлю вас на невнимательном чтении документации. 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. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=DS= 0 9 октября, 2010 Опубликовано 9 октября, 2010 (изменено) · Жалоба Разработчики 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хх? Изменено 9 октября, 2010 пользователем =DS= Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться