реклама на сайте
подробности

 
 
 
Closed TopicStart new topic
> Непонятки с прерываниями M430F2122
rabbit-dj
сообщение Nov 9 2009, 01:47
Сообщение #1





Группа: Участник
Сообщений: 5
Регистрация: 11-07-09
Пользователь №: 51 138



Имеется следующая программка:

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 игнорируются. Если отключить таймер, прием идет нормально. Объясните чайнику, в чем загвоздка?
Go to the top of the page
 
+Quote Post
rezident
сообщение Nov 9 2009, 16:48
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(rabbit-dj @ Nov 9 2009, 06:47) *
Объясните чайнику, в чем загвоздка?
Если вы посмотрите в datasheet раздел interrupt vector addresses и таблицу, приведенную там, то сможете заметить, что прерывания от TimerA имеют больший приоритет, чем прерывания от модуля USCI. И еще учитывайте, что при вызове любого прерывания флаг GIE автоматически сбрасывается. Поэтому вложенные прерывания невозможны, если вы сами не разрешите их принудительной установкой GIE внутри прерывания.
Go to the top of the page
 
+Quote Post
rabbit-dj
сообщение Nov 9 2009, 18:39
Сообщение #3





Группа: Участник
Сообщений: 5
Регистрация: 11-07-09
Пользователь №: 51 138



Спасибо, я тоже грешу на приоритет. Но как совместить работу таймера и USCI понять не могу. Может что посоветуете?
Go to the top of the page
 
+Quote Post
rezident
сообщение Nov 9 2009, 19:07
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Вы сначала опишите алгоритм вашей программы. Т.е. чего вы от нее хотите и что она делает у вас "по-факту"? Потому, что на самом деле нет каких-то особых проблем при одновременном использовании таймера(ов) и модуля(ей) USCI.
Go to the top of the page
 
+Quote Post
rabbit-dj
сообщение Nov 9 2009, 19:50
Сообщение #5





Группа: Участник
Сообщений: 5
Регистрация: 11-07-09
Пользователь №: 51 138



Программа должна делать следующее. На таймере организована динамическая индикация для управления 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 не обрабатываются, данные не принимаются.
Go to the top of the page
 
+Quote Post
rezident
сообщение Nov 9 2009, 21:14
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(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;
  }
}
Go to the top of the page
 
+Quote Post
rabbit-dj
сообщение Nov 9 2009, 21:53
Сообщение #7





Группа: Участник
Сообщений: 5
Регистрация: 11-07-09
Пользователь №: 51 138



Так и есть. Усе заработало, спасибо ОГРОМНОЕ!!! Тему можно закрывать.
Go to the top of the page
 
+Quote Post

Closed TopicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 8th July 2025 - 02:59
Рейтинг@Mail.ru


Страница сгенерированна за 0.01447 секунд с 7
ELECTRONIX ©2004-2016