Jump to content

    
Sign in to follow this  
Herz

Освоение MSP430 / первые шаги

Recommended Posts

Решил я, на старости лет, освоить MSP430. Наверное напрасно: после ПИКов - голова кругом. Но уже жаль потраченного времени, чтобы отступить. Поэтому пока не сдаюсь.

Купил LaunchPad на FR2355, установил Code Composer Studio v.9, полистал немного доки. Именно "немного", потому что их - вагон, а садиться за парту, как обычно, времени нет. Поэтому обучение приходится проводить "в процессе".

Подключил по I2C сенсор TMP275 с целью освоения заодно этого интерфейса. Раньше с ним не работал, всегда предпочитал SPI. 

Нашёл на просторах сети простенький пример работы с I2C от какого-то индуса, немного подправил.

Пока использую поллинг флага запонения приёмного регистра - вроде всё работает:

1. Записиваю число 0х00 в Pointer Register сенсора. Мол, читать буду регистр температуры. Проходит, получаю ACK.

2. Читаю температурный регистр, получаю адекватное значение температуры. Но, читаю только первый байт, остальные не интересуют. Потому сразу посылаю STOP.

3. Повторяю всё в цикле, выглядит нормально. Смущает немного только некоторая задержка (30мкс) между чтением и записью. Частота клока - 132кГц. Частота DCO (по умолчанию) - 2МГц.

 */

#include <msp430.h> 

// Direction mode of I2c bus (0 - transmit, 1 - receive)
unsigned char Dir_Mode = 0;
unsigned char TXByteCtr;        // transmit bytes counter
int PRxData;                    // received data
int i;                          // counter
unsigned char Pointer;          // content of pointer register byte

// P0, P1 codes of Pointer Register for internal TMP275 addressing
int const Temp_REG = 0;
int const Config_REG = 1;

int const itgAddress = 0x4F;


void init_I2C(void);
void Transmit(void);
void Receive(void);
/**
 * main.c
 */
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;       // stop watchdog timer

    // Set P1.4 to output direction
    P1DIR |= BIT4;

    // Disable the GPIO power-on default high-impedance mode
    // to activate previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;

    P4SEL0 |= BIT6 + BIT7;           // Assign I2C pins to USCI_B1

    init_I2C();

    Pointer = Temp_REG;

      while(1)
      {
          //Transmit process
          Dir_Mode = 0;
          Transmit();
          while (UCB1CTL1 & UCTXSTP);             // Ensure stop condition got sent
          //Receive process
          Dir_Mode = 1;
          Receive();
          while (UCB1CTL1 & UCTXSTP);             // Ensure stop condition got sent
      }
}

void init_I2C(void)
{
      UCB1CTL1 |= UCSWRST;                      // Enable SW reset
      UCB1CTLW0 |= UCMST + UCMODE_3;             // I2C Master, synchronous mode
      UCB1BRW = 8;                             // fSCL = SMCLK/8
      UCB1CTLW1 = UCASTP_2;                     // automatic stop assertion
      UCB1TBCNT = 1;                            // TX only 1 byte of data
      UCB1I2CSA = itgAddress;                   // Slave Address is 0x4Fh
      UCB1CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      UCB1IE |= UCRXIE0 + UCTXIE0;               //Enable RX and TX interrupt
//    __bis_SR_register(GIE);                    // Enable global interrupts
}

void Transmit(void)
{
    UCB1CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
    while (UCB1CTL1 & UCTXSTT);                 // Start condition sent?

    UCB1TXBUF = Pointer;
}

void Receive(void)
{
        UCB1CTL1 &= ~UCTR ;                     // Clear UCTR (set Receiver mode)
        UCB1CTL1 |= UCTXSTT;                    // I2C start condition
        P1OUT |= BIT4;                          // P1.4 on (LED on)
        while (UCB1CTL1 & UCTXSTT);             // Start condition sent?
        while (!(UCB1IFG & UCRXIFG0));

        UCB1CTL1 |= UCTXSTP;                    // I2C stop condition, after one byte only
        PRxData = UCB1RXBUF;                    // Get RX data
}

20200511-0001_32.thumb.gif.fea0a2e2c6a815caad1a959ddd6bd695.gif

Но, если пытаюсь заменить поллинг прерыванием, выползает странность.

1. Записи числа 0х00 в Pointer Register не происходит.

2. Чтение по-прежнему выполняется (только потому, что в Pointer Register сохранился адрес температурного регистра).

3. После чтения STOP-condition не проходит, хотя в продпрограмме обработки прерывания я его посылку прописал, и даже дожидаюсь окончания. Вместо этого сразу начинается следующая запись.

 */

#include <msp430.h> 

// Direction mode of I2c bus (0 - transmit, 1 - receive)
unsigned char Dir_Mode = 0;
unsigned char TXByteCtr;        // transmit bytes counter
int PRxData;                    // received data
int i;                          // counter
unsigned char Pointer;          // content of pointer register byte

// P0, P1 codes of Pointer Register for internal TMP275 addressing
int const Temp_REG = 0;
int const Config_REG = 1;

int const itgAddress = 0x4F;


void init_I2C(void);
void Transmit(void);
void Receive(void);
/**
 * main.c
 */
int main(void)
{
    WDTCTL = WDTPW | WDTHOLD;       // stop watchdog timer

    // Set P1.4 to output direction
    P1DIR |= BIT4;

    // Disable the GPIO power-on default high-impedance mode
    // to activate previously configured port settings
    PM5CTL0 &= ~LOCKLPM5;

    P4SEL0 |= BIT6 + BIT7;           // Assign I2C pins to USCI_B1

    init_I2C();

    Pointer = Temp_REG;

      while(1)
      {
          //Transmit process
          Dir_Mode = 0;
          Transmit();
          while (UCB1CTL1 & UCTXSTP);             // Ensure stop condition got sent
          //Receive process
          Dir_Mode = 1;
          Receive();
          while (UCB1CTL1 & UCTXSTP);             // Ensure stop condition got sent
      }
}

void init_I2C(void)
{
      UCB1CTL1 |= UCSWRST;                      // Enable SW reset
      UCB1CTLW0 |= UCMST + UCMODE_3;             // I2C Master, synchronous mode
      UCB1BRW = 8;                             // fSCL = SMCLK/8
      UCB1CTLW1 = UCASTP_2;                     // automatic stop assertion
      UCB1TBCNT = 1;                            // TX only 1 byte of data
      UCB1I2CSA = itgAddress;                   // Slave Address is 0x4Fh
      UCB1CTL1 &= ~UCSWRST;                     // Clear SW reset, resume operation
      UCB1IE |= UCRXIE0 + UCTXIE0;               //Enable RX and TX interrupt
    __bis_SR_register(GIE);                    // Enable global interrupts
}

void Transmit(void)
{
    UCB1CTL1 |= UCTR + UCTXSTT;                 // I2C TX, start condition
    while (UCB1CTL1 & UCTXSTT);                 // Start condition sent?

    UCB1TXBUF = Pointer;
}

void Receive(void)
{
        UCB1CTL1 &= ~UCTR ;                     // Clear UCTR (set Receiver mode)
        UCB1CTL1 |= UCTXSTT;                    // I2C start condition
        P1OUT |= BIT4;                          // P1.4 on (LED on)
        while (UCB1CTL1 & UCTXSTT);             // Start condition sent?
//      while (!(UCB1IFG & UCRXIFG0));

//        UCB1CTL1 |= UCTXSTP;                    // I2C stop condition, after one byte only
//        PRxData = UCB1RXBUF;                    // Get RX data
}

//-------------------------------------------------------------------------------
// Interrupt routine
//
//-------------------------------------------------------------------------------
#pragma vector = EUSCI_B1_VECTOR
__interrupt void EUSCI_B1_TX_ISR(void)
{
    switch(__even_in_range(UCB1IV,0x1e))
    {
        case 0x00: // Vector 0: No interrupts
        break;
        case 0x02:  // Vector 2: ALIFG, Arbitration lost
        break;
        case 0x04:  // Vector 4: NACKIFG, Not acknowledgment
        break;
        case 0x06:  // Vector 6: STTIFG, Start condition received
        break;
        case 0x08:  // Vector 8: STPIFG, Stop condition received
        break;
        case 0x0a:  // Vector 10: RXIFG3, Slave 3 Data received
        break;
        case 0x0c:  // Vector 12: TXIFG3, Slave 3 Transmit buffer empty
        break;
        case 0x0e:  // Vector 14: RXIFG2, Slave 2 Data received
        break;
        case 0x10:  // Vector 16: TXIFG2, Slave 2 Transmit buffer empty
        break;
        case 0x12:  // Vector 18: RXIFG1, Slave 1 Data received
        break;
        case 0x14:  // Vector 20: TXIFG1, Slave 1 Transmit buffer empty
        break;
        case 0x16:  // Vector 22: RXIFG0, Data received, receiver buffer is full
      P1OUT &= ~BIT4;                   // P1.4 off
      PRxData = UCB1RXBUF;              // Get RX data
      UCB1CTL1 |= UCTXSTP;              // I2C stop condition
      while (UCB1CTL1 & UCTXSTP);       // wait for stop pass
        break;
        case 0x18:  // Vector 24: TXIFG0, Transmit buffer is empty
        break;
        case 0x1a:  // Vector 26: BCNTIFG, Byte counter zero
        break;
        case 0x1c:  // Vector 28: clock low time-out
        break;
        case 0x1e:  // Vector 30: 9th bit
        break;
        default: break;
    }
}

 

20200511-0002_32.thumb.gif.4a0b709db8d82b853eeea3e26eafc3ab.gif

Здесь зелёный луч - состояние пина P1.4, это я пытаюсь проконтролировать время от посылки START-a  в режиме Recieve до собственно начала обработки прерывания по заполнению буфера приёмника. Выходит, что обработка начинается уже в период записи (Transmit), хотя сам Transmit начаться, вроде бы, не должен, пока STOP от чтения не пройдёт (см. строку   while (UCB1CTL1 & UCTXSTP);       // wait for stop pass )...

Что тут происходит?

Share this post


Link to post
Share on other sites

А чего вы именно за MSP430 взялись? Из-за аналоговых плюшек? Мы вот потихоньку пытаемся с них сползти через 20 лет работы с ними. Бедность периферии просто выводила из себя.
По вашему вопросу я может скажу неправду, т.к. с FR серией никогда не работал, но в сериях F1xxx и F2xxx периферийный модуль I2C был просто безобразный по неудобству работы и по наличию странных проблем в дизайне. Короче, за последние 10 лет я несколько раз делал попытки его применить, и натыкаясь на очередную бяку опускал руки :acute:
Все I2C функции и до меня и у меня на фирме работают чисто программно. Все наглядно и просто, но правда, поллинг.

Share this post


Link to post
Share on other sites
23 минуты назад, Baser сказал:

По вашему вопросу я может скажу неправду, т.к. с FR серией никогда не работал, но в сериях F1xxx и F2xxx периферийный модуль I2C был просто безобразный по неудобству работы и по наличию странных проблем в дизайне.

Не надо возводить напраслину на MSP430! Хотя я делал всего один проект на нём (MSP430FR5739), но с существенными проблемами не сталкивался. I2C использовал и, естественно, аппаратный и естественно - без поллингов, по прерываниям. Всё нормально там.

48 минут назад, Herz сказал:

3. После чтения STOP-condition не проходит, хотя в продпрограмме обработки прерывания я его посылку прописал, и даже дожидаюсь окончания. Вместо этого сразу начинается следующая запись.

Что-то как-то странно у Вас выглядит ISR. Я конечно давно уже занимался MSP430 и многое забыл, но что-то у Вас там сильно много чего не хватает. Обрабатывается только UCRXIFG0...

Ещё и цикл ожидания внутри ISR! Бррр....

Share this post


Link to post
Share on other sites
10 hours ago, Baser said:

А чего вы именно за MSP430 взялись?

Купился на низкое потребление, всякие там LPM... Хотя, если разобраться, то не так уж важно. Но впервые слышу о том, что сам МК плохой. Вроде много чего на нём (них) сделано.

10 hours ago, jcxz said:

Что-то как-то странно у Вас выглядит ISR. Я конечно давно уже занимался MSP430 и многое забыл, но что-то у Вас там сильно много чего не хватает. Обрабатывается только UCRXIFG0...

Ещё и цикл ожидания внутри ISR! Бррр....

Согласен, некрасиво. Но так было сделано только для проверки. И именно ситуации с завершением чтения - посылкой STOP. Так и не понятно, отчего она не проходит.

Share this post


Link to post
Share on other sites
13 минут назад, Herz сказал:

Купился на низкое потребление, всякие там LPM... Хотя, если разобраться, то не так уж важно. Но впервые слышу о том, что сам МК плохой. Вроде много чего на нём (них) сделано.

И не жалейте! Хорошее семейство. Для своей ниши. Особенно радует то, что есть встроенная FRAM. Мне в своё время очень понравилась их система тактирования, с удобным отключением неиспользуемых частот + режимы LPM (у меня было батарейное устройство) с удобным входом/выходом из них.

Share this post


Link to post
Share on other sites
11 часов назад, jcxz сказал:

Не надо возводить напраслину на MSP430! Хотя я делал всего один проект на нём (MSP430FR5739), но с существенными проблемами не сталкивался. I2C использовал и, естественно, аппаратный и естественно - без поллингов, по прерываниям. Всё нормально там.

Напраслину я не возвожу и сверх меры не хаю :acute:
Само ядро и система команд очень неплохая. И во время старта производства, начало 2000-х, MSP430 был прорывом. По потреблению с ним никто тогда не мог соревноваться. Но времени прошло много.
Еще раз скажу, что серии с FRAM я не применял, может быть они существенно новее и лучше. И сама технология FRAM выглядит очень привлекательно.
 

43 минуты назад, Herz сказал:

Купился на низкое потребление, всякие там LPM... Хотя, если разобраться, то не так уж важно. Но впервые слышу о том, что сам МК плохой. Вроде много чего на нём (них) сделано.

Нормальная серия МК, но уже некоторое время назад его представители общего применения начали проигрывать АРМ-ам. А вот специализированные серии MSP430 - хороши.
Я пару лет назад смотрел, на чем делать новые проекты (старые были на MSP430F1xx и F2xx) и ничего хорошего не выбрал. В сериях F1xx и F2xx периферия очень бедная, серии F5xx и F6xx уже проигрывали по потреблению, да и улучшение периферии было небольшим.
Сейчас перехожу на STM32, т.к. по критериям скорость+периферия+потребление+цена, у STM32 можно выбрать лучший вариант, чем у MSP430.

з.ы. сейчас глянул, что Тексас наковал сотни новых MSP430 с разными буковками - возможно они сделали шаг вперед. А так, 15 лет они топтались на месте.

Share this post


Link to post
Share on other sites
7 minutes ago, Baser said:

серии F5xx и F6xx уже проигрывали по потреблению, да и улучшение периферии было небольшим.
Сейчас перехожу на STM32, т.к. по критериям скорость+периферия+потребление+цена, у STM32 можно выбрать лучший вариант, чем у MSP430.

По потреблению сейчас всех уделывает RE от Renesas - https://www.renesas.com/us/en/products/microcontrollers-microprocessors/re.html

А MSP430 давно морально устарели.
Применяли их в аналоговых модулях ПЛК Сименс, потому и живы до сих пор.
Но это не значит что индивидуальные разработчики должны на них западать. 

Share this post


Link to post
Share on other sites
55 minutes ago, alexunder said:
59 minutes ago, AlexandrY said:

По потреблению сейчас всех уделывает RE от Renesas - https://www.renesas.com/us/en/products/microcontrollers-microprocessors/re.html

а как же кинетисы? :biggrin:

А как же EFM32 ? :biggrin:

Share this post


Link to post
Share on other sites
23 hours ago, Herz said:

. . . Подключил по I2C сенсор TMP275 с целью освоения заодно этого интерфейса. Раньше с ним не работал, всегда предпочитал SPI. 

. . . Нашёл на просторах сети простенький пример работы с I2C от какого-то индуса, немного подправил.

 

C I2C довольно отдельная песТня, тк много-чего зависит от слейва. Сильно желательно использование лог. анализатора.

В качестве примеров я всегда брал "родные" Ti (хотя пишут теже индусы многие). Конкретно для FR2355 у меня нет, вот на 

MSP430FR57xx_Code_Examples. "Преемственность" периферии во-многом сохраняется, есть документация "Migration to . . ".

Есть также пакет msp430_driverlib_1_97_00_19.zip - там на все проц-ры, в т.ч. FR2x  (сюда выложить не получается по размеру)

slac491d.zip

part_MSP430FR2xx_4xx.zip

Share this post


Link to post
Share on other sites

Спасибо, я практически всё это находил, но...

1) Примеры от Тексаса слишком "наворочены" как для меня, начинающего. Они там попытались объять все случаи и сделать унивесальные библиотеки, но вышло очень громоздко и запутано.

2) Я сознательно не хочу "перескакивать" на другие примеры, пока не разберусь, почему не работает этот. Для меня важнее найти ошибку, чем найти работающий код. Хотя, возможно, выбора не останется, придётся сравнивать...

Share this post


Link to post
Share on other sites

 

 

В 12.05.2020 в 00:07, Herz сказал:

20200511-0002_32.thumb.gif.4a0b709db8d82b853eeea3e26eafc3ab.gif

Здесь зелёный луч - состояние пина P1.4, это я пытаюсь проконтролировать время от посылки START-a  в режиме Recieve до собственно начала обработки прерывания по заполнению буфера приёмника. Выходит, что обработка начинается уже в период записи (Transmit), хотя сам Transmit начаться, вроде бы, не должен, пока STOP от чтения не пройдёт (см. строку   while (UCB1CTL1 & UCTXSTP);       // wait for stop pass )...

Что тут происходит?

Видно три цветных блока (Оранжевый №1, Синий, Оранжевый №2)

1. Первый оранжевый блок - START+Addr+R (вероятно это он)

2. Синий блок - считанный первый байт

3. После этого наступает прерывание по приёму байта (зеленый луч=0)

4. Второй оранжевый блок - считанный второй байт, и вероятно после этого состояние STOP.

 

Причина чтения двух байт вместо одного - в обработчике прерывания флаг STOP устанавливается после прочтения регистра данных, а это запускает чтение следующего байта.

А чтобы прочитался только один байт, нужно установить флаг STOP перед прочтением регистра данных. Т.е. в обработчике прерывания поменять местами строки

В 12.05.2020 в 00:07, Herz сказал:

PRxData = UCB1RXBUF; // Get RX data

UCB1CTL1 |= UCTXSTP; // I2C stop condition

 

Edited by controller_m30

Share this post


Link to post
Share on other sites

И еще один момент: после получения последнего байта ведущий должен выставить на шину NAK вместо ACK. Это заставит ведомого прекратить выдавать биты на шину и позволит ведущему сформировать STOP или повторный START после окончания NACK (в противном случае ведомый начнет в этом месте выдавать первый бит следующего байта, который может оказаться нулем и не позволит сформировать STOP или START). При беглом просмотре вашего кода из первого сообщения никаких упоминаний NACK я не увидел.

Share this post


Link to post
Share on other sites

Не разглядел, что на картинке второй оранжевый блок это запись START+Addr+W. Но байта данных за ним нет...

Пока видится два варианта:

1. Выключить прерывание Transmit в команде инициализации 

UCB1IE |= UCRXIE0 + UCTXIE0;               //Enable RX and TX interrupt

Потому что этот обработчик пустой, и может это как-то влияет на нежелание передавать байт данных.

 

2. Или прерывание не выключать, а перенести в обработчик этого прерывания команду

UCB1TXBUF = Pointer;

Может из обработчика данные всё-же отправятся.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this