Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Непонятки с прерываниями M430F2122
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > MSP430
rabbit-dj
Имеется следующая программка:

CODE
int __low_level_init(void)
{
int res=0;
WDTCTL = WDTPW +WDTHOLD; // Stop Watchdog Timer
if (CALBC1_8MHZ ==0xFF || CALDCO_8MHZ == 0xFF)
{
while(1); // If calibration constants erased
// do not load, trap CPU!!
}
BCSCTL1 = CALBC1_8MHZ; // Set DCO to 8MHz
DCOCTL = CALDCO_8MHZ;
//------ Èíèöèàëèçàöèÿ USART â ðåæèìå I2C -----------------
P3SEL |= 0x06; // Assign I2C pins to USCI_B0
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMODE_3 + UCSYNC; // I2C Slave, synchronous mode
UCB0I2COA = 0x48; // Own Address is 048h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0I2CIE |= UCSTPIE + UCSTTIE; // Enable STT and STP interrupt
IE2 |= UCB0RXIE; // Enable RX interrupt
//------ Èíèöèàëèçàöèÿ TIMER_B ---------
TA1CCR0 = 30000;
TA1CTL = TASSEL_2 + MC_1; // SMCLK, upmode
TA1CCTL1 |= CCIE; // TACCR0 interrupt enabled

//---------------------------------------------------------
__enable_interrupt(); // Ãëîáàëüíîå ðàçðåøåíèå ïðåðûâàíèé
return 0;
}
//===========================================================
int main( void )
{

while (1)
{
PRxData = (unsigned char *)RxBuffer; // Start of RX buffer

if(RxComplete == 1)
{
RxComplete = 0;
write_flash(RxBuffer);
RXByteCtr = 0;
}
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt
}
}
//------------------------------------------------------------------------------
// The USCI_B0 data ISR is used to move received data from the I2C master
// to the MSP430 memory.
//------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
*PRxData++ = UCB0RXBUF; // Move RX data to address PRxData
RXByteCtr++; // Increment RX byte count

}
//------------------------------------------------------------------------------
// The USCI_B0 state ISR is used to wake up the CPU from LPM0 in order to
// process the received data in the main program. LPM0 is only exit in case
// of a (re-)start or stop condition when actual data was received.
//------------------------------------------------------------------------------
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
UCB0STAT &= ~(UCSTPIFG + UCSTTIFG); // Clear interrupt flags
if (RXByteCtr) // Check RX byte counter
{
RxComplete = 1;
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0 if data was
}
}
//=============================================================
#pragma vector=TIMER1_A1_VECTOR
__interrupt void TIMERA1_isr( void ) //
{

}
//======================= Çàïèñü âî ôëýø ========================
void write_flash(volatile unsigned int *Data)
{
unsigned int *Flash_ptr; // Flash pointer
char i;

Flash_ptr = (unsigned int *)SegOfData; // Initialize Flash pointer
FCTL3 = FWKEY; // Clear Lock bit
FCTL1 = FWKEY + ERASE; // Set Erase bit
*Flash_ptr = 0; // Dummy write to erase Flash seg
FCTL1 = FWKEY + WRT; // Set WRT bit for write operation
for (i = 0; i < 32; i++)
{
*Flash_ptr++ = Data[i]; // Write value to flash
}
FCTL1 = FWKEY; // Clear WRT bit
FCTL3 = FWKEY + LOCK; // Set LOCK bit

}


В ней ведется прием по шине I2C и работает интервальный таймер. Проблема в том, что при разрешенном прерывании от таймера прерывания от модуля USCI игнорируются. Если отключить таймер, прием идет нормально. Объясните чайнику, в чем загвоздка?
rezident
Цитата(rabbit-dj @ Nov 9 2009, 06:47) *
Объясните чайнику, в чем загвоздка?
Если вы посмотрите в datasheet раздел interrupt vector addresses и таблицу, приведенную там, то сможете заметить, что прерывания от TimerA имеют больший приоритет, чем прерывания от модуля USCI. И еще учитывайте, что при вызове любого прерывания флаг GIE автоматически сбрасывается. Поэтому вложенные прерывания невозможны, если вы сами не разрешите их принудительной установкой GIE внутри прерывания.
rabbit-dj
Спасибо, я тоже грешу на приоритет. Но как совместить работу таймера и USCI понять не могу. Может что посоветуете?
rezident
Вы сначала опишите алгоритм вашей программы. Т.е. чего вы от нее хотите и что она делает у вас "по-факту"? Потому, что на самом деле нет каких-то особых проблем при одновременном использовании таймера(ов) и модуля(ей) USCI.
rabbit-dj
Программа должна делать следующее. На таймере организована динамическая индикация для управления 4-разрядным 7-сегментным LED-дисплеем, т.е. управление переключением анодов разрядов LED. Одновременно с индикацией должен работать USCI на прием данных (показания индикатора и яркость), сохранять их во флеш и оперативно обновлять показания. Аноды переключаются через мультиплексор 74НС4051. Цифра загружается в мксх 74HC595.
Вот код, который я накарябал:

CODE

#define EN_SW_DIR P1DIR
#define EN_SW_OUT P1OUT
#define EN_SW_PIN P1OUT_0 //Вывод разрешения работы мультиплексора 74HC4051
#define S_DIR P1DIR
#define S_OUT P1OUT
#define Shift_DIR P2DIR
#define Shift_OUT P2OUT
#define Shift_PIN P2OUT_0 //Вывод сдвига мс. 74HC595
#define Data_DIR P2DIR
#define Data_OUT P2OUT
#define Data_PIN P2OUT_1 //Вывод данных мс. 74HC595
#define Storage_DIR P2DIR
#define Storage_OUT P2OUT
#define Storage_PIN P2OUT_2 //Вывод обновления мс. 74HC595
#define Light_DIR P2DIR
#define Light_OUT P2OUT
#define Light_PIN P2OUT_4 //Вывод ШИМ управления яркостью
#define S_0 P1OUT_3 //Выход Y0 мультиплексора 74HC4051
#define S_1 P1OUT_2 //Выход Y1 мультиплексора 74HC4051
#define S_2 P1OUT_1 //Выход Y2 мультиплексора 74HC4051
#define OwnAddress 0x02//Адрес ведомого модуля №1
#define SegOfData 0x1000//Адрес начала сегмента пользовательских данных
#define Light 0x1000//Адрес переменной яркости свечения табло
#define Price ((0x1000)+OwnAddress)
//Адрес переменной значения цены модуля
//================================================
volatile unsigned int i;
unsigned char *PRxData; // Pointer to RX data
unsigned char RXByteCtr;
volatile unsigned int RxBuffer[64]; // Allocate 64 byte of RAM
volatile unsigned int RxComplete;

unsigned char digit_out[4], cur_dig;

const unsigned int buf[] = { //массив с цифрами
0xDF, //0
0x43, //1
0x7E, //2
0x77, //3
0xE3, //4
0xB7, //5
0xBF, //6
0x47, //7
0xFF, //8
0xF7, //9
0x00
};

void hc595_wr(char dig);
void HEX_TO_BCD_TO_LED(int in);
void write_flash(volatile unsigned int *Data);

//=============
int __low_level_init(void)
{
WDTCTL = WDTPW +WDTHOLD; // Stop Watchdog Timer
if (CALBC1_8MHZ ==0xFF || CALDCO_8MHZ == 0xFF)
{
while(1); // If calibration constants erased
// do not load, trap CPU!!
}
BCSCTL1 = CALBC1_8MHZ; // Set DCO to 8MHz
DCOCTL = CALDCO_8MHZ;

BCSCTL2 |= DIVS_3;
//------ Инициализация Портов Ввода/Вывода ----
//----- Порт 1 -----
P1DIR = 0xFF;
EN_SW_OUT |= EN_SW_PIN;
//----- Порт 2 -----
P2DIR = 0xFF;
Light_DIR |= Light_PIN; // 2.4 output
P2SEL |= Light_PIN; // 2.4 TA1_1 otion
//Light_OUT |= Light_PIN;//1 на выходе PWM
//----- Порт 3 -----
//------ Инициализация USART в режиме I2C -----------------
P3SEL |= 0x06; // Assign I2C pins to USCI_B0
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMODE_3 + UCSYNC; // I2C Slave, synchronous mode
UCB0I2COA = 0x48; // Own Address is 048h
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
UCB0I2CIE |= UCSTPIE + UCSTTIE; // Enable STT and STP interrupt
IE2 |= UCB0RXIE; // Enable RX interrupt
//------ Инициализация TIMER_A ---------
TACCR0 = 200; // PWM период
TACCTL2 = OUTMOD_7; // TA0CCR2 toggle/set
TACCR2 =200; // TA1CCR1 PWM duty cycle
TACTL = TASSEL_2 + MC_1; // SMCLK, up mode
//------ Инициализация TIMER_B ---------
TA1CCR0 = 30000;
TA1CTL = TASSEL_2 + MC_1+ID_3; // SMCLK, upmode
TA1CCTL1 |= CCIE; // TACCR0 interrupt enabled

//---------------------------------------------------------
__enable_interrupt(); // Глобальное разрешение прерываний
return 0;
}
//===========================================================
int main( void )
{

unsigned int *CarPrice = 0, *CarLight = 0;
while (1)
{
PRxData = (unsigned char *)RxBuffer; // Start of RX buffer

if(RxComplete == 1)
{
RxComplete = 0;
write_flash(RxBuffer);
RXByteCtr = 0;
}
CarLight = (unsigned int *)Light;
TACCR2 = *CarLight&(0xFF);
CarPrice = (unsigned int *)Price;
HEX_TO_BCD_TO_LED(1234);
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupt
}

}
//------------------------------------------------------------------------------
// The USCI_B0 data ISR is used to move received data from the I2C master
// to the MSP430 memory.
//------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
*PRxData++ = UCB0RXBUF; // Move RX data to address PRxData
RXByteCtr++; // Increment RX byte count

}
//------------------------------------------------------------------------------
// The USCI_B0 state ISR is used to wake up the CPU from LPM0 in order to
// process the received data in the main program. LPM0 is only exit in case
// of a (re-)start or stop condition when actual data was received.
//------------------------------------------------------------------------------
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
UCB0STAT &= ~(UCSTPIFG + UCSTTIFG); // Clear interrupt flags
if (RXByteCtr) // Check RX byte counter
{
RxComplete = 1;
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0 if data was
}
}
//=============================================================
#pragma vector=TIMER1_A1_VECTOR
__interrupt void TIMERA1_isr( void ) //
{
EN_SW_OUT |= EN_SW_PIN; //Гащение разряда
if (cur_dig ==0)
{
S_OUT &=~ (S_0|S_1|S_2); //Разряд 1
}
else if (cur_dig ==1)
{
S_OUT |= S_0; //Разряд 2
}
else if (cur_dig ==2)
{
S_OUT &=~ (S_0);
S_OUT |= S_1; //Разряд 3
}
else
{
S_OUT |= (S_0|S_1); //Разряд 4
}
hc595_wr(digit_out[cur_dig]); //Загрузка цифры в 74НС595
EN_SW_OUT &=~ EN_SW_PIN; //Зажигание разряда
cur_dig++;
if (cur_dig==4) cur_dig=0;
}
//============================================================
void hc595_wr(char dig)
{ //подпрограмма вывода данных в регистр
char a;
Storage_OUT |= Storage_PIN;//поднимаем линию Storage в лог.1
for(a=0; a<8; a++)
{ //цикл для вывода 8 бит данных из массива
char d = buf[dig] & 1<<a;
if(d)
Data_OUT |= Data_PIN; //выводим в линию DATA текущий бит
else Data_OUT &=~Data_PIN;
Shift_OUT &=~Shift_PIN; //опускаем линию CLK в лог.0
Shift_OUT |= Shift_PIN; //поднимаем линию CLK в лог.1
}
Storage_OUT &=~ Storage_PIN; //опускаем линию Storage в лог.0
}
//============================================================================
void HEX_TO_BCD_TO_LED(int in)
{
digit_out[0]=in/1000;
digit_out[1]=(in%1000)/100;
digit_out[2]= (in%100)/10;
digit_out[3]=in%10;
}
//======================= Запись во флэш ========================
void write_flash(volatile unsigned int *Data)
{
unsigned int *Flash_ptr; // Flash pointer
char i;

Flash_ptr = (unsigned int *)SegOfData; // Initialize Flash pointer
FCTL3 = FWKEY; // Clear Lock bit
FCTL1 = FWKEY + ERASE; // Set Erase bit
*Flash_ptr = 0; // Dummy write to erase Flash seg
FCTL1 = FWKEY + WRT; // Set WRT bit for write operation
for (i = 0; i < 32; i++)
{
*Flash_ptr++ = Data[i]; // Write value to flash
}
FCTL1 = FWKEY; // Clear WRT bit
FCTL3 = FWKEY + LOCK; // Set LOCK bit

}


//===================================================================



А по факту получатся, что пока идут прерывания от таймера, прерывания от USCI не обрабатываются, данные не принимаются.
rezident
Цитата(rabbit-dj @ Nov 10 2009, 00:50) *
А по факту получатся, что пока идут прерывания от таймера, прерывания от USCI не обрабатываются, данные не принимаются.
Досконально не разбирался, просмотрел "по-диагонали". Комментирую только то, что заметил сходу.
Вы используете прерывание от регистра compare TACCR1. Но почему-то забыли (или пропустили эту информацию) о том, что вектор прерывания TIMER1_A1_VECTOR расшарен с тремя источниками прерываний: TACCR1 CCIFG, TACCR2 CCIFG, и TAIFG. А "заведует" ими регистр TAIV. Пока вы программно не прочитаете содержимое TAIV, источник прерывания останется активным. Т.е. в вашей программе постоянно вызывается прерывание по вектору TIMER1_A1_VECTOR и поэтому до менее приоритетных прерываний от модуля USCI дело просто не доходит. Прочитайте внимательно раздел 12.2.6 Timer_A Interrupts главы Timer_A в MSP430x2xx Family User's Guide, там есть пример TAIV Software Example.
Вектор должен быть оформлен примерно так
Код
#pragma vector=TIMER1_A1_VECTOR
#pragma type_attribute=__interrupt
void TIMER1_A1_ISR(void)
{ switch(TA1IV)
  { case TA1IV_TACCR1:
                           //<-здесь должно быть содержимое вашего прерывания
      break;
    case TA1IV_TAIFG:
    default:
      break;
  }
}
rabbit-dj
Так и есть. Усе заработало, спасибо ОГРОМНОЕ!!! Тему можно закрывать.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.