Sida 1 av 2

Timer problem

Postat: 2 juni 2008, 21:32:01
av Eriktronix
Jag håller på med ett litet test projekt där jag använder en PIC18F2431. Jag får inte timer-avbrotten att fungera, kan någon se något fel i min kod. uppkopplingen består bara av PIC:en strömförsörjning samt anslutning till en IDC2 och två avkopplings kondigar. Jag har även två stycken pull-up motstånd för FLTA och FLTB

Kod: Markera allt

#include <p18cxxx.h>
#include <pcpwm.h>
#include <timers.h>

#pragma config WDTEN = OFF
#pragma config OSC = IRC
#pragma config LVP = OFF

//--- DEFINITIONS --- DEFINITIONS --- DEFINITIONS ---

#define TRM0_OFFSET 25540

//--- PROTOTYPES --- PROTOTYPES --- PROTOTYPES ---

void timer_isr(void);
void timer_config(void);
void pcpwm_config( void );
void loop_50_hz( void);

//--- VARIABLES --- VARIABLES --- VARIABLES ---

//--- CODE --- CODE --- CODE ---

void pcpwm_config( void )
{
	PORTB = 0;
	TRISB = 0b11000000;
	
	TRISC = 0b00000010;
	
	DTCON = 0b00000000;
	PTCON0 = 0b00000101;
	
	PTPERH = 0x05;
	PTPERL = 0x34;	//F_pwm = 400Hz	
	
	PWMCON0 = 0b01011111;
    PWMCON1 = 0b00001001;
    PTCON1 = 0b00000000;
    FLTCONFIG = 0b00000011;
    
    PDC0H = 0x05; 
    PDC0L = 0xf0;
    
    PDC1H = 0x0B; 
    PDC1L = 0x28;
    
    PDC2H = 0x12; 
    PDC2L = 0xd0;			
}


#pragma code low_vector = 0x18
void interrupt_at_low_vector(void)
{
	_asm GOTO timer_isr _endasm
}

#pragma code

#pragma interruptlow timer_isr

void timer_isr(void)
{
	INTCONbits.TMR0IF = 0; //Clear interrupt flag
	
	loop_50_hz();
	
	WriteTimer0( TRM0_OFFSET );
}

void timer_config(void)
{
	OpenTimer0( TIMER_INT_ON	&
				T0_16BIT		&
				T0_SOURCE_INT	&
				T0_EDGE_RISE	&
				T0_PS_1_1 );
				
	WriteTimer0( TRM0_OFFSET );
	
	INTCONbits.GIE = 1;		//Allow interrupts
}

void loop_50_hz( void)
{
	PTCON1bits.PTEN = 1;
}

void main( void )
{
	OSCCON = 0x72;		//Sets F_osc to 8MHz
	
	loop_50_hz();
	
	timer_config();		//Low pri interupt 50Hz
	
	pcpwm_config();		//Single-shot mode 400Hz
	
	while (1);
}

Postat: 2 juni 2008, 23:16:06
av sodjan
Vad händer ?
Du kanske skulle minska ner koden till enbart det som du vill testa.

Postat: 3 juni 2008, 19:34:18
av Eriktronix
Det var en av de första sakerna jag testade, dock utan resultat. Jag har även testat att byt PIC:en, men inte heller det ger något resultat. Jag har den senaste versionen av MPLAB IDE, kan det finnas någon inställning som måste göras. I övrigt exekveras koden som den ska.

Postat: 3 juni 2008, 20:21:24
av sodjan
> > Du kanske skulle minska ner koden till enbart det som du vill testa.

> Det var en av de första sakerna jag testade, dock utan resultat.

Då borde du visa *den* koden, så att vi bara behöver läsa det viktiga.
Visa den minsta möjliga kod som uppvisar det problem du ser !

Jag ser inte att du clearar RCON.IPEN. I.o.f.s ska den vara "0" vid
reset, men...

Sedan kan du strunta i Open/Write timer funktionerna och skriva direkt
till de aktuella registren. D.v.s koppla bort så mycket libr.funktioner
som möjligt...

Men viktigast, banta ner koden till det minsta möjliga som uppvisar
problemet.

Postat: 3 juni 2008, 22:41:38
av Eriktronix
Okej... här kommer ett försök till att skriva alla fuktioner själv...
Jag har tagit bort allt "onödigt". För att se att jag får ett avbrott tänder jag en led som förväntas slockna så fort jag får ett avbrott. Detta sker inte.

Kod: Markera allt

#include <p18cxxx.h>

#pragma config WDTEN = OFF
#pragma config OSC = IRC
#pragma config LVP = OFF

//--- DEFINITIONS --- DEFINITIONS --- DEFINITIONS ---

#define TIMER_OFFSET 25536

#define LOWBYTE(v)   ((unsigned char) (v))
#define HIGHBYTE(v)  ((unsigned char) (((unsigned int) (v)) >> 8))

//--- PROTOTYPES --- PROTOTYPES --- PROTOTYPES ---

void init(void);
void init_clk(void);
void init_timer(void);
void init_interrupts(void);
void set_offset_timer( unsigned int o );
void timer_isr(void);

//--- VARIABLES --- VARIABLES --- VARIABLES ---

//--- CODE --- CODE --- CODE ---

#pragma code low_vector = 0x18
void interrupt_at_low_vector(void)
{
	_asm GOTO timer_isr _endasm
}

#pragma code

#pragma interruptlow timer_isr

void timer_isr(void)
{
	INTCONbits.TMR0IF = 0; //Clear interrupt flag
	
                set_offset_timer( TIMER_OFFSET );

	PORTCbits.RC3 = 0;
}
void init_clk()
{
	OSCCON = 0x72;		//Sets F_osc to 8MHz
}

void set_offset_timer( unsigned int o )
{
	TMR0H = HIGHBYTE( o );
	
	TMR0L = LOWBYTE( o );
}

void init_timer()
{
	T0CON = 0b00001000;
	 
	set_offset_timer( TIMER_OFFSET );
	
	init_interrupts();
	
	T0CONbits.TMR0ON = 1; // Start timer
}

void init_interrupts(void)
{
	RCONbits.IPEN = 0; // Disable priority levels
	
	INTCON = 0b01100000;
	
	INTCONbits.TMR0IF = 0; // Clear interrupt flag
	
	INTCON2bits.TMR0IP = 1; // Enable interrupts
}

void init(void)
{
	init_clk();
	
	init_timer();
	
	INTCONbits.GIE = 1;
}

void main( void )
{
	TRISC = 0;
	
	PORTCbits.RC3 = 1;
	
	init();

	while (1)
	{
		// wait for interrupt.
	}

Postat: 3 juni 2008, 22:54:01
av spaderkung
En titt i kompilerad asm kan vara på sin plats.

Postat: 3 juni 2008, 23:25:57
av sodjan
OK, jag har ingen direkt ide, men om det var jag som hade problemet
så skulle jag:

- Förenkla koden så att den bli lättare att följa.
D.v.s plocka bort alla helt onödiga funktioner, skriv allt rakt av
i main().

- Skriva en kort ASM kod som gör samma sak för att verifiera funktionen.

- Lägg till *alla* CONFIG flaggor, så att inget är missat.

Postat: 4 juni 2008, 14:03:32
av vfr
Jag tycker Sodjans idéer är bra. Vid felsökning gäller det hela tiden (enligt min mening) att förenkla problemställningen så långt att man slutligen bara har problemet kvar. Då är det inga problem att hitta det.

Postat: 4 juni 2008, 14:12:49
av sodjan
Jag skulle kanske lägga till en 4'de punkt, "Ge inte upp"... :-) :-)

Jag skulle även plocka bort skrivningen till TMR0, låt
den vara "free-running" och få *det* att fungera först.

Lägg till en poll i main() på TMR0IF flaggan för att verifiera
att *den* sätts i alla fall.

> RCONbits.IPEN = 0; // Disable priority levels
> #pragma code low_vector = 0x18

Om int-prio-level är disablat så sker alla interrupt till h'0008'.
Se databladet !!

Postat: 4 juni 2008, 21:12:16
av Eriktronix
Hej på er, tack för visat intresse! Här kommer dagen uppdatering. Jag har försökt att göra det ni föreslår. TMR0IF sätts när TMR0L går från 0xFF till 0x00 med det blir aldrig något avbrott. Jag inte säker på i vilken ordning man bör sätt alla "inställningar" i registren.

Kod: Markera allt

#include <p18f2431.h>

#pragma config WDTEN = OFF
#pragma config OSC = IRCIO
#pragma config LVP = OFF

void timer_isr(void);

#pragma code low_vector = 0x18

void interrupt_at_low_vector(void)
{
	_asm GOTO timer_isr _endasm
}

#pragma code

#pragma interruptlow timer_isr

void timer_isr(void)
{
	INTCONbits.TMR0IF = 0;		// Pull down TMR0 interrupt flag
	
	PORTCbits.RC3 = 0;
	
	INTCONbits.GIEL = 1;		// Enables low-prio interrupts
	
	T0CONbits.TMR0ON = 1;		// Enables Timer0 
}

void main( void )
{
	OSCCON = 0x72;				// Sets F_osc to 8MHz
	
	TRISC = 0;
	
	PORTCbits.RC3 = 0;
	
	PORTCbits.RC3 = 1;
	
	T0CONbits.T016BIT = 1;		// 16-bit mode
	T0CONbits.T0CS = 0;			// Internal instruction cycle clock
	T0CONbits.T0SE = 0;			// Rising edge
	T0CONbits.PSA = 1;			// By-pass prescaler	
	
	RCONbits.IPEN = 1;			// Enables piro levels
	
	INTCONbits.GIEH = 0;		// Disable high-prio interrupts
	INTCONbits.TMR0IE = 1;		// Enable timer0 overflow interrupt
	INTCONbits.INT0IE = 0;		// Disable External interrupts
	INTCONbits.RBIE = 0;		// Disable portB interrupts
	INTCONbits.TMR0IF = 0;		// Pull down TMR0 interrupt flag
	INTCONbits.INT0IF = 0;		// Pull down INT0 interrupt flag
	INTCONbits.RBIF = 0;		// Pull down portb interrupt flag
	
	INTCON2bits.TMR0IP = 0;		// Timer0 interrupt prio = low 
	
	INTCONbits.GIEL = 1;		// Enables low-prio interrupts
	
	T0CONbits.TMR0ON = 1;		// Enables Timer0 

	while (1)
	{
		// wait for interrupt.
	}
}

Postat: 4 juni 2008, 23:06:52
av sodjan
> Jag har försökt att göra det ni föreslår.

Men misslyckats.

Kolla mitt senaste inlägg igen. Du kan inte ha läst det eftersom
du inte ens kommenterar det kanske viktigaste i inlägget,
adressen för interruptrutinen...

Postat: 10 juni 2008, 18:42:39
av Eriktronix
Okej... du har rätt jag testade inte med att bara använda en prio-nivå. Men nu har jag det och det fungerar nu! Men va f-n är det som gör att det inte fungerar men två prio-nivårer??? Återstår att lösa...

Tack för all hjälp och alla förslag!

Postat: 10 juni 2008, 22:01:23
av sodjan
> Men va f-n är det som gör att det inte fungerar men två prio-nivårer???

Det gör det nog om du gör rätt... :-)

> Återstår att lösa...

Varför det ? Behöver du det (d.v.s 2 nivåer) ?

Postat: 10 juni 2008, 22:47:45
av Eriktronix
Jag funderar på om jag behöver det. Jag är av den naturen att jag inte kan lämna ett problem olöst.

Allt är möjligt :)

Postat: 11 juni 2008, 00:53:04
av sodjan
I 99 fall av 100 behövs det inte.
Och om man inte måste köra med 2 nivåer, så bara
ställe det till mer besvär, t.ex genom att det inte finns
"shadow" register till mer än en nivå...