Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: MSP430 I2C & RTC зависаю на while ((~I2CIFG) &ARDYIFG);
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
Bom_Shankar
Уважаемые знатоки...внимание вопрос.
Почему-то первый раз проходя в отладчике это место, флаг выставляется, но в real-time не выставляется, и после второго раза пошагового исполнения всё равно зависаю на ожидании флага.
Вот код, может у меня глаз замылился уже, подскажите кто видит ошибку.
void i2c_write_byte (unsigned char SlaveAddress, unsigned char Addr, unsigned char Byte)
{
I2CIE |= TXRDYIE;
I2CIFG &= ~ARDYIFG;
I2CIFG &= ~TXRDYIFG;
I2CIFG &= ~RXRDYIFG;
i2c_finish = 0;
I2CSA = SlaveAddress;
I2CNDAT = 0x02;
i2c_tx_n = 1;
U0CTL |= MST;
i2c_buf[0] = Byte;
i2c_buf[1] = Addr;
I2CTCTL |= I2CTRX + I2CSTT;
while ((~I2CIFG) &ARDYIFG); // ВОТ ЗДЕСЬ ФЛАГ НЕ ВЫСТАВЛЯЕТСЯ (иногда реальные данные уходят //и ложаться в микруху
while (i2c_finish == 0);
}

void init_i2c(void)
{
P3SEL |= 0x0a; // Assign I2C pins to module
U0CTL |= I2C + SYNC ; // Switch USART0 to I2C mode
U0CTL &= ~I2CEN; // Recommended I2C init procedure
I2CTCTL = I2CSSEL_1; // ACLK
I2CPSC = 0x00; // I2C prescaler
I2CSCLH = 40; // High period of SCL
I2CSCLL = 40; // Low period of SCL // 7372800 / 22 = 335khz
I2CIE = RXRDYIE + RXRDYIE + NACKIE;
U0CTL |= I2CEN; // Enable I2C, 7 bit addr,
_EINT(); // Enable interrupts
}


Заранее большое спасибо.
shanti_shanti@mail.ru
rezident
Как-то замысловато вы проверяете флаг. Зачем инвертировать содержимое регистра при проверке всего лишь одного бита? Кроме затрудения понимания смыла это операция еще и оверхед на пару команд создает. Сравните сами
Код
//   55 while (~I2CIFG&ARDYIFG); // ВОТ ЗДЕСЬ ФЛАГ НЕ ВЫСТАВЛЯЕТСЯ (иногда реальные данные уходят и ложаться в микруху
??i2c_write_byte_0:
        MOV.B    &0x51, R11
        XOR.B    #0xff, R11
        BIT.B    #0x8, R11
        JNE    ??i2c_write_byte_0
Попробуйте написать попроще, например, так
Код
while ((I2CIFG&ARDYIFG)==0);


Получится
Код
//   55 while ((I2CIFG&ARDYIFG)==0); // ВОТ ЗДЕСЬ ФЛАГ НЕ ВЫСТАВЛЯЕТСЯ (иногда реальные данные уходят и ложаться в микруху
??i2c_write_byte_0:
        BIT.B    #0x8, &0x51
        JNC    ??i2c_write_byte_0

Явное сравнение с нулем всегда более корректно компилируется и более доступно для понимания смысла операции.
По самой проверке флага, который якобы не устанавливается.
Вы внимательно прочитали описание событий по которому ARDYIFG устанавливается? Раздел 15.2.8 I2C Interrupts из User's Guide.

Кроме того в строке
Код
I2CIE = RXRDYIE + RXRDYIE + NACKIE;
У вас дважды суммируется флаг RXRDYIE, что дает неправильную маску для I2CIE (0x22, вместо желаемых 0x12).
Вся процедура инициализации неправильно построена. См. пояснения в разделе 15.2.1 I2C Module Initialization из User's Guide. Там приведен вполне конкретный порядок для инициализации регистров USART в режиме I2C.
Ну и другое по мелочи. Типа вроде как используете прерывания, а процедуру обработки прерываний от I2C здесь не привели.
Сергей Борщ
Цитата(rezident @ Mar 12 2007, 18:24) *
Код
I2CIE = RXRDYIE + RXRDYIE + NACKIE;
У вас дважды суммируется флаг RXRDYIE, что дает неправильную маску для I2CIE (0x22, вместо желаемых 0x12).
А я все думал, почему меня все время тянет такие комбинации через "или" делать. Когда все правильно, разницы нет. А вот с такой плюхой... спасибо, запишу аргумент на корочку.
Bom_Shankar
Спасибо за оперативность и профессионализм. А также за уместную критику - сделал всё как Вы сказали(НО ПОКА БЕЗ РЕЗУЛЬТАТА): и последовательность инициалцизации и проверку флага.

Кстати, насчёт флага я посмотрел, вроде это то что нужно, цитирую, ARDYIFG
Прерывание «регистр доступен для чтения». Этот флаг устанавливается, когда ранее
запрограммированный перенос завершен, и биты статуса обновлены. Это прерыва-
ние используется для уведомления ЦПУ о том, что регистры I2C готовы к доступу.

В прерывании я сделал проще некуда

#pragma vector=USART0TX_VECTOR
__interrupt void I2C_ISR(void)
{
switch(I2CIV)
{

case 10: // Receive Ready
//if(i2c_n < 10)
i2c_buf[i2c_n] = I2CDRB;
i2c_n++;
I2CIE &= ~RXRDYIE;
break;
case 12:
I2CDRB = i2c_buf[i2c_tx_n];
i2c_tx_n --;
if(i2c_tx_n < 0)
I2CIE &= ~TXRDYIE; // disable interrupts
break; // Transmit Ready
}
}

Привидите пожалуйста пример в образовательных целях, если есть у кого. Спасибо.

Цитата(rezident @ Mar 12 2007, 19:24) *
Как-то замысловато вы проверяете флаг. Зачем инвертировать содержимое регистра при проверке всего лишь одного бита? Кроме затрудения понимания смыла это операция еще и оверхед на пару команд создает. Сравните сами
Код
//   55 while (~I2CIFG&ARDYIFG); // ВОТ ЗДЕСЬ ФЛАГ НЕ ВЫСТАВЛЯЕТСЯ (иногда реальные данные уходят и ложаться в микруху
??i2c_write_byte_0:
        MOV.B    &0x51, R11
        XOR.B    #0xff, R11
        BIT.B    #0x8, R11
        JNE    ??i2c_write_byte_0
Попробуйте написать попроще, например, так
Код
while ((I2CIFG&ARDYIFG)==0);


Получится
Код
//   55 while ((I2CIFG&ARDYIFG)==0); // ВОТ ЗДЕСЬ ФЛАГ НЕ ВЫСТАВЛЯЕТСЯ (иногда реальные данные уходят и ложаться в микруху
??i2c_write_byte_0:
        BIT.B    #0x8, &0x51
        JNC    ??i2c_write_byte_0

Явное сравнение с нулем всегда более корректно компилируется и более доступно для понимания смысла операции.
По самой проверке флага, который якобы не устанавливается.
Вы внимательно прочитали описание событий по которому ARDYIFG устанавливается? Раздел 15.2.8 I2C Interrupts из User's Guide.

Кроме того в строке
Код
I2CIE = RXRDYIE + RXRDYIE + NACKIE;
У вас дважды суммируется флаг RXRDYIE, что дает неправильную маску для I2CIE (0x22, вместо желаемых 0x12).
Вся процедура инициализации неправильно построена. См. пояснения в разделе 15.2.1 I2C Module Initialization из User's Guide. Там приведен вполне конкретный порядок для инициализации регистров USART в режиме I2C.
Ну и другое по мелочи. Типа вроде как используете прерывания, а процедуру обработки прерываний от I2C здесь не привели.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.