Problemas com a interrupção FIQ e IRQ

Software e Hardware para linha ARM

Moderadores: 51, guest2003, Renie, gpenga

Problemas com a interrupção FIQ e IRQ

Mensagempor rod_ladeira » 12 Dez 2008 20:31

Bom dia senhores...

Estou com o seguinte problema: Eu habilito a interrupção FIQ e depois a IRQ, mas aleatóriamente essas interrupção são desabilitadas....sendo que em nenhum momento do código eu uso o registrador para desabilitar a interrupção....[/b]
Projetos eletrônicos......
www.angoera.com.br
rod_ladeira
Bit
 
Mensagens: 33
Registrado em: 17 Dez 2007 14:37
Localização: São Paulo

Mensagempor styg » 15 Dez 2008 11:07

no tratamento da sua interrupção voce esta reescrevendo esse registrador ?

VICVectAddr = 0xFFFFFFFF;

faço isso em todas as rotinas de tratmento de int, senao fizer isso, senao me engano ele se perde..
Lucas
Avatar do usuário
styg
Word
 
Mensagens: 799
Registrado em: 16 Out 2006 08:24
Localização: Floripa abaixo de zero.

Mensagempor MarcusPonce » 15 Dez 2008 11:47

Para entender melhor:
O firmware começa a executar e depois de atender várias vezes (um número aleatório) às FIQ e IRQs ele muda e não atende a mais nenhuma, só se der reset ? Ou deixa de atender somente a algumas das solicitações mas atende à maioria delas ?

Você certamente pretende interromper a rotina de atendimento a uma IRQ para atender uma FIQ, certo ? Você saberia informar se é neste momento que o problema acontece ?
MarcusPonce
Byte
 
Mensagens: 166
Registrado em: 12 Fev 2007 13:58
Localização: Campinas - SP

Mensagempor rod_ladeira » 04 Fev 2009 09:21

O problema ocorre logo que as interrupções são iniciadas..ou seja, ao ligar o sistema ou ele funciona sem problemas ou nao inicia, trava logo na primeira interrupção.

No tratamento da interrupção eu escrevo sim VICVectAddr = 0xFFFFFFFF;

Obrigado pelas respostas......
Projetos eletrônicos......
www.angoera.com.br
rod_ladeira
Bit
 
Mensagens: 33
Registrado em: 17 Dez 2007 14:37
Localização: São Paulo

Mensagempor rod_ladeira » 04 Fev 2009 09:24

o código de inicialização das interrupões estão abaixo:

void IRQ_Init(void){

// MA_SetISRAddress_VIC((U32 *)&Timer_1ms_Int, 5, 0x08); //
VICVectAddr0 = (unsigned long)Trata_IRQ;
VICVectCntl0 = 0x20 | 8; // pwm


VICDefVectAddr = (unsigned long) DefISR;
MA_SetPortOut_GPIO(0,PORT_FREQA);
MA_SetPortOut_GPIO(0,PORT_FREQB);
MA_SetPortOut_GPIO(0,PORT_FREQC);
MA_WritePort_GPIO(0,0,PORT_FREQA);
MA_WritePort_GPIO(0,PORT_FREQB,PORT_FREQB);
MA_WritePort_GPIO(0,0,PORT_FREQC);
MA_Init_PWM0();
MA_Start_PWM0(1); // inicia e reseta

/* Default Vector Address Register */


}

void Freq_Init(void){

MA_Init_TIMER();
MA_Reset_TIMER() ;
MA_Start_TIMER(0,1);
MA_Start_TIMER(1,1);
VICIntEnable |= 0x00000030;
}
Projetos eletrônicos......
www.angoera.com.br
rod_ladeira
Bit
 
Mensagens: 33
Registrado em: 17 Dez 2007 14:37
Localização: São Paulo

Mensagempor MarcusPonce » 04 Fev 2009 19:11

Realmente um comportamento estranho...

O trecho do firmware que você colocou aqui mostra o seguinte:

Se o PWM conseguir disparar uma interrupção, ela será atendida pela rotina Trata_IRQ(). Provavelmente em MA_Init_PWM0() existe uma configuração que habilita uma situação na qual o PWM gera uma interrupção e em algum lugar existe VICIntEnable |= ( 1 << 8 ) para habilitar o VIC a ser disparado pelo PWM.

Por outro lado, existe no seu código VICIntEnable |= 0x00000030; que habilita o VIC a receber interrupções dos TIMERS 0 e 1, mas não vejo você associar os endereços de rotinas para tratar estas interrupções dos TIMERS no VIC. Desta maneira as interrupções dos TIMERS serão tratadas pela rotina DefISR, que é a default.

É isso mesmo que você quer que aconteça ?

Ainda persiste o fato de só às vezes travar. Você inicializou os TIMERS de maneira que os CAPTURE 0-3 podem gerar interrupção ? Se sim, a rotina que trata as interrupções dos timers está realmente escrevendo "1" nos bits correspondentes do registrador IR para resetar o pedido de interrupção ? OU será que um CAPTURE foi habilitado por engano e pode gerar uma interrupção que não está sendo resetada ?
MarcusPonce
Byte
 
Mensagens: 166
Registrado em: 12 Fev 2007 13:58
Localização: Campinas - SP

Mensagempor rod_ladeira » 05 Fev 2009 09:00

Olá....

Exatamente, a função MA_Init_PWM0() tem o código:

void MA_Init_PWM0( void )

{


/*--- Initialise registers ---*/


PWMMR0 = MA_PWMMR0_PWM0;
PWMMR1 = MA_PWMMR1_PWM0;
PWMMR2 = MA_PWMMR2_PWM0;
PWMMR3 = MA_PWMMR3_PWM0;
PWMMR4 = MA_PWMMR4_PWM0;
PWMMR5 = MA_PWMMR5_PWM0;
PWMMR6 = MA_PWMMR6_PWM0;
PWMTCR = MA_PWMTCR_PWM0;
PWMMCR = MA_PWMMCR_PWM0;
PWMPCR = MA_PWMPCR_PWM0;

PWMLER = 0x0000007f;
VICIntEnable |= 0x00000100; // hab int pwm

} /* MA_Init_PWM0 */


As interrupcoes do Timer 0 e 1 sao tratados pela Interrupcao FIQ:

VICIntSelect = 0x00000030; /* Interrupt Select Register */

Ou seja eu seto os timers na funcao Freq_Init();


Os tratamentos de interrupcoes sao realizados pelas funcoes:

Trata_IRQ() e Trata_FIQ();

O código do Startup.s que faz esse endereçamento esta abaixo:

Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
LDR PC, DAbt_Addr
NOP ; Reserved Vector
LDR PC, IRQ_Addr
LDR PC, FIQ_Addr
LDR PC, [PC, #-0x0FF0] ; Vector from VicVectAddr


Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler

Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
IRQ_Handler B Trata_IRQ
FIQ_Handler B Trata_FIQ
Projetos eletrônicos......
www.angoera.com.br
rod_ladeira
Bit
 
Mensagens: 33
Registrado em: 17 Dez 2007 14:37
Localização: São Paulo

Mensagempor rod_ladeira » 05 Fev 2009 09:09

As interrupcoes IRQ sao nao vetoriadas e esta habilitado as interrupções UART0, PWM e Browm Out detect.

VICIntEnable |= 0x00100170;

Abaixo encontra-se o tratamento da interrupção IRQ

__irq void Trata_IRQ(void){ // timer de 1ms utilizando o pwm

static char Modo_freqA = DOWN, count = 0, count_amostra = 0;
int canal;
int i;
int status;
static int status_a=0;




VICIntEnable |= 0x00000170;
PWMLER = 0x0000007F;
if(PWMIR == 0x00000004){ // interrupção de geração das frequencias de leitura do mux
count++;
if(Modo_freqA == UP){
Modo_freqA = DOWN;
MA_WritePort_GPIO(0,0,PORT_FREQA);
PWMMR2 = PWMTC + ALTO_4051;
}
else if(Modo_freqA == DOWN){ // nivel UP
Modo_freqA = UP;
MA_WritePort_GPIO(0,PORT_FREQA,PORT_FREQA);

PWMMR2 = PWMTC + BAIXO_4051;
}
else{//volta do intervalo
MA_WritePort_GPIO(0,0,PORT_FREQA);
MA_WritePort_GPIO(0,PORT_FREQB,PORT_FREQB);
MA_WritePort_GPIO(0,0,PORT_FREQC);
PWMMR2 = PWMTC + ALTO_4051;
Modo_freqA = DOWN;
count = 0;
}
if(count == BAIXO_B){
MA_WritePort_GPIO(0,0,PORT_FREQB);
}
if(count == ALTO_C){
MA_WritePort_GPIO(0,PORT_FREQC,PORT_FREQC);
}
if(count == COUNT_INTERV){
Modo_freqA = INTERVALO;
PWMMR2 = PWMTC + INTERV_4051;
}
status_a = ~(IO0PIN);
for(i=0;i<100;i++);
MA_WritePort_GPIO(0,0,ReadConv); // faz a coversão do AD
for(i=0;i<100;i++); // aproximadamente 5us
MA_WritePort_GPIO(0,ReadConv,ReadConv); // Converte para asaida do conversor AD
PWMMR3 = PWMTC + TEMPO_CONVERSAO;
PWMTCR &= ~(0x00000001);
PWMIR &= 0x00000004;
PWMTCR |= (0x00000001);
}
else if(PWMIR == 0x00000008){



canal = MASK_CANAL & status_a;

switch(canal){
case MOLEA:
Mole[0] += Valor_AD();
break;
case MOLEB:
Mole[2] += Valor_AD();
break;
case MOLEC:
Mole[4] += Valor_AD();
break;
case DUROA:
Duro[0] += Valor_AD();
break;
case DUROB:
Duro[2] += Valor_AD();
break;
case DUROC:
Duro[4] += Valor_AD();
if(count_amostra < 3)
count_amostra++;
else{
count_amostra = 0;
for(i=0;i<N_CANAIS;i+=2){
Duro[i] /= 4;
Mole[i] /= 4;
}
flag_hab_tratamento = true;

if(flag_hab_portico){ // Portico habilitado
if(!hab_infra){
Trata_Sinal();
for(i=0;i<N_CANAIS;i+=2){
Duro[i] = 0;
Mole[i] = 0;
}
}
else
i = (IO0PIN);
i >>= 15;
i &= 0x00000001;
if(i){
if(!flag_infra_temp)
passagens++;
LigaRelogio(RelInfra,KInfra);
flag_infra = true;
flag_infra_temp = true;
}
else
flag_infra_temp = false;
if(flag_infra){ // infra hab e = 0
Trata_Sinal();
for(i=0;i<N_CANAIS;i+=2){
Duro[i] = 0;
Mole[i] = 0;
}
}
}
if(flag_bargraph){ // Leitura do Bargraph
flag_bargraph = false;
for(i=0;i<N_CANAIS;i+=2){
if(Mole[i] > Duro[i])
Bar[i] = (int)((Mole[i] - Duro[i])/150);
else
Bar[i] = (int)((Duro[i] - Mole[i])/150);
if(Bar[i] > 15)
Bar[i] = 15;
Duro[i] = 0;
Mole[i] = 0;
}
flag_atualiza_barg = true;
}

}

break;
}
PWMTCR &= ~(0x00000001);
PWMIR &= 0x00000008;
PWMTCR |= (0x00000001);
}
else {

PWMTCR &= ~(0x00000001);
PWMIR &= 0x00000002;
PWMTCR |= (0x00000001);
PWMMR1 = PWMTC + TIMER_1ms;
PWMTCR &= ~(0x00000001);
PWMMR0 = PWMTC + 1;
PWMTCR |= (0x00000001);

Relogios ();
if((flag_delay_ms == false) && (count_ms != 0 ))
count_ms--;
else if (count_ms == 0)
flag_delay_ms = true;


}
PWMTCR &= ~(0x00000001);
PWMMR0 = PWMTC + 1; // atualiza registradores
PWMTCR |= (0x00000001);

if(VICIRQStatus & 0x00100000)
Grava_EEPROM();


if(VICIRQStatus & 0x00000040){ //serial
//Trata_Serial();

status = MA_GetChar_UART0(&serial);
if( (status & 0x01) && (count_serial < 30) ){

buffer_serial[count_serial] = serial;
count_serial++;
}
}
VICVectAddr = 0xFFFFFFFF;

}


Tratamento da interrupção FIQ:

__irq void Trata_FIQ(void){

WDFEED = 0xAA;
WDFEED = 0x55;

if(T0IR != 0)
switch(T0IR){
//case 0x00000000:

//break;
case 0x00000002: // canal 1
if(Timer_1 == DOWN){
T0MR1 = T0MR1 + Alto_1;
Timer_1 = UP;
}
T0IR = 0x00000002;
break;

case 0x00000001: // canal 0
if(Timer_0 == DOWN){
T0MR1 = T0MR0 + Baixo_1;
Timer_0 = UP;
Timer_1 = DOWN;
}
else
Timer_0 = DOWN;;
T0MR0 = T0MR0 + Periodo_1;
T0IR = 0x00000001;
break;

case 0x00000008: // canal 3
if(Timer_3 == DOWN){
T0MR3 = T0MR3 + Alto_2;
Timer_3 = UP;
}
T0IR = 0x00000008;
break;

case 0x00000004: // canal 2

if(Timer_2 == DOWN){
T0MR3 = T0MR2 + Baixo_2;
Timer_2 = UP;
Timer_3 = DOWN;
}
else
Timer_2 = DOWN;
T0IR = 0x00000004;
T0MR2 = T0MR2 + Periodo_2;
break;



default:
byte_shadow.BYTE = T0IR;
if(byte_shadow.BIT.BIT1){
if(Timer_1 == DOWN){
T0MR1 = T0MR1 + Alto_1;
Timer_1 = UP;
}
T0IR = 0x00000002;
}
if(byte_shadow.BIT.BIT3){
if(Timer_3 == DOWN){
T0MR3 = T0MR3 + Alto_2;
Timer_3 = UP;
}
T0IR = 0x00000008;
}
if(byte_shadow.BIT.BIT0){
if(Timer_0 == DOWN){
T0MR1 = T0MR0 + Baixo_1;
Timer_0 = UP;
Timer_1 = DOWN;
}
else
Timer_0 = DOWN;;
T0MR0 = T0MR0 + Periodo_1;
T0IR = 0x00000001;
}
break;
}
if(T1IR != 0)
switch(T1IR){

case 0x00000002: // canal 1
if(Timer1_1 == DOWN){
T1MR1 = T1MR1 + Alto_3;
Timer1_1 = UP;
}
T1IR = 0x00000002;
break;
case 0x00000001: // canal 0
if(Timer1_0 == DOWN){
T1MR1 = T1MR0 + Baixo_3;
Timer1_0 = UP;
Timer1_1 = DOWN;
}
else
Timer1_0 = DOWN;
T1MR0 = T1MR0 + Periodo_3;
T1IR = 0x00000001;
break;

default:

if(Timer1_1 == DOWN){
T1MR1 = T1MR1 + Alto_3;
Timer1_1 = UP;
}
T1IR = 0x00000002;
break;

}
VICVectAddr = 0xFFFFFFFF;
}

Obrigado pelos replays........
Projetos eletrônicos......
www.angoera.com.br
rod_ladeira
Bit
 
Mensagens: 33
Registrado em: 17 Dez 2007 14:37
Localização: São Paulo

Mensagempor MarcusPonce » 08 Fev 2009 17:07

O código que você postou é claramente uma parte pequena de um firmware relativamente complexo. Assim, não deu para ter certeza do que está errado, mas se você me permite sugiro algumas modificações nas rotinas de tratamento de interrupção.
A idéia básica é que antes de sair da rotina que trata da interrupção temos que resetar o flag que causou a interrupção, sem depender de outros eventos. Isso parece meio óbvio mas dependendo de como o código é escrito fica difícil imaginar todas as possibilidades e se alguma delas escapar então o código vai falhar ou travar apenas raramente.

No código que você postou, no tratamento da IRQ, existe a possibilidade de ficar travado. Considere estas linhas:
__irq void Trata_IRQ(void)
{
...
VICIntEnable |= 0x00000170;
...
if(PWMIR == 0x00000004)
{
...
PWMIR &= 0x00000004;
...
}
else if(PWMIR == 0x00000008)
{
...
PWMIR &= 0x00000008;
...
}
else
{
...
PWMIR &= 0x00000002;
...
}
...
if(VICIRQStatus & 0x00100000)
Grava_EEPROM();

if(VICIRQStatus & 0x00000040)
{ //serial
//Trata_Serial();
status = MA_GetChar_UART0(&serial);
...
}
VICVectAddr = 0xFFFFFFFF;
}


Proponho o seguinte:

a) Mudar os dois " if (PWMIR == 0x0000000n) " para " if (PWMIR & 0x0000000n) ". Da forma como está, se acontecer de PWMIR = 0x0000000C ou PWMIR = 0x0000000E então nunca mais estes dois bits serão resetados e a rotina de tratamento de interrupção vai consumir todo o tempo do ARM. Veja que interessante: para os dois bits estarem setados ao mesmo tempo basta que a __outra__ rotina de interrupção Trata_FIQ esteja começando a executar quando o primeiro é setado e ciclos depois (antes da Trata_FIQ terminar) o segundo bit seja setado.

b) Na linha " if(VICIRQStatus & 0x00000040) " está o teste para tratar a interrupção serial, mas o reset desta interrupção só acontece se hoje ele estiver dentro da " MA_GetChar_UART0(&serial); " . Seria melhor você verificar qual a causa de interrupção serial (umas 4 ou 5 causas possíveis, depende de você ter habilitado), tratar e resetar aqui dentro da rotina de interrução.

c) Na primeira vez que esta rotina Trata_IRQ de interrupção for chamada, será desabilitada a interrupção do BOD. É isso mesmo que você quer ?

d) Na rotina Trata_FIQ também existe uma situação semelhanto ao item (a). Lá, se acontecer de T0IR estiver com 2 ou mais bits setados então a interrupção do T0 só vai ser resetada se os " byte_shadow.BIT.BITn " correspondentes não estiverem 0. Como no trecho de código postado não existe a definição de byte_shadow.BIT, só posso suspeitar que seja composta de uma union com byte_shadow.BYTE. Ficaria mais fácil de entender o código e mais fácil de prever o que vai acontecer se você trocasse do original abaixo:

if(T0IR != 0)
switch(T0IR)
{
case 0x00000001:
...
case 0x00000002:
...
case 0x00000004:
...
case 0x00000008:
...
default:
( alguns "if"s consultando byte_shadow.BIT.BITn )
...
}

para a forma:

if (T0IR & 0x00000001)
{
...
}
if (T0IR & 0x00000002)
{
...
}
if (T0IR & 0x00000004)
{
...
}
if (T0IR & 0x00000008)
{
...
}


Uma última recomendação: Logo após o reset você espera meio ou um segundo em loop antes de começar a rodar o programa e ativar a interrupção por BOD ? É para que a alimentação se estabilize.

Por favor depois informe se melhorou ou se descobriu alguma coisa.
MarcusPonce
Byte
 
Mensagens: 166
Registrado em: 12 Fev 2007 13:58
Localização: Campinas - SP

Mensagempor Renato » 10 Fev 2009 17:34

Muito bom Ponce.
Se puderes descrever um pequeno código "para estudante", tipo liga led,
contendo uma FIC (BOD pode ser) e 2 IRQ vetorada (EINT0 e TIMER
comparação), para entender melhor esse mecanismo das INT do ARM.
Desde já grato.
Renato
Byte
 
Mensagens: 224
Registrado em: 20 Out 2006 08:35


Voltar para ARM

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

cron

x