|
|
View previous topic :: View next topic |
Author |
Message |
Jonatan
Joined: 17 Jun 2010 Posts: 5 Location: Stockholm - Sweden
|
Problems with timer 1 interrupt |
Posted: Thu Jun 17, 2010 2:47 am |
|
|
Hi!
My trouble is getting the timer1 to trigger. I presume its something in the initialization code. My chip is 16F887 and the code is temporary downsized to the following test code:
Code: |
#include <16F887.h>
//#INT_TIMER1
void Timer_isr(void);
unsigned int8 flag;
void main(){
// delay_ms(500); //wait 500ms for system to stabilize
setup_oscillator(OSC_8MHZ, 0);
setup_timer_0(RTCC_INTERNAL);
shiftreg = 0;
out_shiftreg();
//Set port direction
set_tris_a(PORT_A); //See io_cfg.h for I/O-configurations
set_tris_b(PORT_B);
set_tris_c(PORT_C);
set_bit(shiftreg, BAT_SENS);
BATTERY_FET_ON();
DCDC2_OFF();
setup_comparator(NC_NC_NC_NC);
/* setup_adc_ports( FUEL_CELL_1_CHANNEL |
FUEL_CELL_2_CHANNEL |
FUEL_CELL_3_CHANNEL |
FUEL_CELL_4_CHANNEL |
FUEL_CELL_SENSE_CHANNEL |
IN_CURRENT_FUEL_CELL_CHANNEL |
FUEL_CELL_TEMP_CHANNEL |
IN_CURRENT_LITHIUM_CELL_CHANNEL |
LITHIUM_CELL_TEMP_CHANNEL |
IN_VOLT_LITHIUM_CHANNEL );
*/
setup_adc( ADC_CLOCK_INTERNAL | VSS_VDD );
set_timer1(TIMER1_0_3125MS); //Set timer1 to interrupt every 312.5us
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //internal clock source and prescale as 1
enable_interrupts(INT_TIMER1); //Enable overflow interrupt Timer1,
//interrupt-routine Timer1_isr() see process.h
enable_interrupts(global); //Enable global interrupt
flag = 7;
for(;;)
{
//All updates in main-loop are dependent on software-timers found in process.h
//and timers are updated in interrupt-routine void Timer1_isr() also found in process.h
// tt++;
// if(tt>18000){
// tt=0;
toggle_shiftreg(LED_3);
out_shiftreg();
//printf("DUMP ADC:\n");
//dump_adc();
printf("\nTimer: %Ld", get_timer1());
printf("\nFlag: %u", flag);
}
}
#INT_TIMER1
void Timer_isr(void){
flag = 121;
set_shiftreg(LED_1_GREEN);
clear_interrupt(int_timer1); //Clear interrupt flag
set_timer1(TIMER1_0_3125MS); //Load timer1-register to interrupt every 312,5us
}
|
The timer interrupt set the int8 flag to 11 as a "witness" and the main loop is constantly printing the timer and this flag to the UART. That way, I can see that the timer is running, but the interrupt is never trigging. What am I doing wrong?
I'm using MPLAB with CCS plugin.
Edit: More info from .LST file: CCS PCM C Compiler, Version 4.085, 47134 |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jun 17, 2010 7:52 am |
|
|
You code is incomplete; several variables and defines are missing.
So for sure we know this is not the code you have been testing with.
Please post a complete program including #fuses, etc, so we can copy/paste it into our IDE.
Make the program as small as possible (remove all the code in comments and non-related function calls). |
|
|
Jonatan
Joined: 17 Jun 2010 Posts: 5 Location: Stockholm - Sweden
|
|
Posted: Thu Jun 17, 2010 8:28 am |
|
|
Ok, I didn't realize something except defines were missing, but here goes (I have streamlined it a bit more):
Main.c:
Code: | #include <16F887.h>
#include <project.h>
#define TIMER1_0_3125MS 0xFD8F //Timer1 interrupts 3200/sec
//** PORT DIRECTIONS ***********************************************************************/
//#define PORT_A 0b00001111 //Port A directions
#define PORT_A 0b00111111
//#define PORT_B 0b00111111 //Port B directions
#define PORT_B 0b11111111
//#define PORT_C 0b00000000 //Port C directions
#define PORT_C 0b10000000
#define PORT_D 0b00001000
#define PORT_E 0b00000000
#define LED_1_RED 0
#define LED_1_GREEN 1
#define LED_2 2
#define LED_3 3
#define LED_4 4
#define LED_5 5
#define LED_6 6
#define LED_7 7
#define LED_8 8
#define LED_9 9
#define DCDC1_ENABLE 10
#define DCDC2PWR 11
#define BAT_SENS 12
#define FC1_LOAD 13
#define FC2_LOAD 14
#define FC3_LOAD 15
#define FC4_LOAD 16
#define LATCH_OUT PIN_D2
#define SHIFT_CLK PIN_D1
#define DATA_IN PIN_D0
#define _BV(abit) (1 << (abit))
#define clear_bit(port, abit) {port = port & ~_BV(abit);}
#define set_bit(port, abit) {port = port | _BV(abit);}
#define toggle_bit(port, abit) {port = port ^ _BV(abit);}
#define set_bitmask(port, mask) {port = port | mask;}
#define clear_bitmask(port, mask) {port = port & ~ mask;}
unsigned int16 shiftreg = 0x00;
#define set_shiftreg(abit) {set_bit(shiftreg, (unsigned int16)abit);}
#define clear_shiftreg(abit) {clear_bit(shiftreg, (unsigned int16)abit);}
#define toggle_shiftreg(abit) {toggle_bit(shiftreg, (unsigned int16)abit);}
unsigned int8 flag;
void out_shiftreg(void);
#int_timer1
void TIMER1_ISR(){
flag = 121;
clear_interrupt(int_timer1); //Clear interrupt flag
set_timer1(TIMER1_0_3125MS); //Load timer1-register to interrupt every 312,5us
}
#INT_DEFAULT
void glob_isr(){
flag=144;
}
void main(){
// delay_ms(500); //wait 500ms for system to stabilize
setup_oscillator(OSC_8MHZ, 0);
setup_timer_0(RTCC_INTERNAL);
setup_wdt(WDT_OFF);
set_tris_a(PORT_A); //See io_cfg.h for I/O-configurations
set_tris_b(PORT_B);
set_tris_c(PORT_C);
set_timer1(TIMER1_0_3125MS); //Set timer1 to interrupt every 312.5us
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //internal clock source and prescale as 1
enable_interrupts(INT_TIMER1); //Enable overflow interrupt Timer1,
enable_interrupts(GLOBAL); //Enable global interrupt
flag = 7;
bit_set(BAUDCTL,4); //Invert the data using UART, if no invert of data bit clear this bit
for(;;)
{
toggle_shiftreg(LED_1_GREEN);
printf("\nTimer: %Ld", get_timer1());
printf("\nFlag: %u", flag);
out_shiftreg();
}
}
void out_shiftreg(void){
unsigned int8 i;
unsigned int16 reg;
reg = shiftreg;
output_bit(LATCH_OUT, 0);
for(i = 0; i < 16; i ++){
if(reg & 0x8000){
output_bit(DATA_IN, 1);
}else{
output_bit(DATA_IN, 0);
}
reg = reg << 1;
output_bit(SHIFT_CLK, 1);
output_bit(SHIFT_CLK, 0);
}
output_bit(LATCH_OUT, 1);
}
|
Project.h:
Code: | /********************************************************************************************
* FileName: project.h *
* Processor: PIC16F886 *
*
* Company: NNNNNNN AB *
* Project: NNN *
* Date: 080122 *
* *
********************************************************************************************/
#ifndef PROJECT_H_
#define PROJECT_H_
//#include <16F886.h>
//#include <16F887.h>
/** C O N F I G U R A T I O N **************************************************************/
// ,BORV21,BROWNOUT_NOSL
#pragma device ADC=10
#fuses NOWDT,NOPROTECT,NOCPD,PUT,NOBROWNOUT,MCLR,INTRC_IO
#use delay(clock=8000000, restart_wdt) // timer0 is the watchdog. restart wdt during delays
// previous clock = 8000000,7500000
//#use rs232(UART1,baud=19200,parity=N,bits=8,restart_wdt)
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
/** RS232 **********************************************************************************/
#define PRINT_STATUS
#ifdef PRINT_STATUS
#define BUFFER_SIZE 10
#use rs232(UART1,force_sw,invert,baud=9600,parity=N,bits=8,restart_wdt,XMIT=PIN_C6)//UART1
#endif
#if __DEVICE__ == 916 || __DEVICE__ == 886 || __DEVICE__ == 887
# pragma byte BAUDCTL = 0x0187
# pragma byte RCSTA = 0x0018
# pragma byte TRISC = 0x0087
#endif
#endif // PROJECT_H_
/** EOF project.h **************************************************************************/ |
The code constantly puts the timer1 value and the "flag" on UART. The flag is updated in the ISRs. |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Jun 17, 2010 10:18 am |
|
|
I forgot to mention I like the example program to be small .
Funny how you are mixing the compiler's internal function bit_set() and your home brew set_bit(). Why not use the compiler's optimized version everywhere?
Same applies to the bit_clear v.s. clear_bit
Several code simplifications are possible:
- There is no need to clear the timer interrupt flag inside the interrupt handler. The compiler does this for you.
- Setting the RS232 invert option by addressing the BAUDCTL option is not in the CCS way. Use the INVERT option in the #use RS232 line instead (surprise, you already have it there !).
- You have defined #use RS232 with 'force_sw' option. This conflicts with the UART1 option. And you know the interrupts will distort communication timings unless you specify DISABLE_INTS?
- For demonstrating the problem you can remove the FAST_IO, led toggling, watchdog, shiftreg stuff.
Removing all the non-important stuff I reduced the program to: Code: | #include <16F887.h>
#fuses NOWDT,NOPROTECT,NOCPD,PUT,NOBROWNOUT,MCLR,INTRC_IO
#use delay(clock=8000000)
#use rs232(UART1,force_sw,invert,baud=9600,parity=N,bits=8,restart_wdt,XMIT=PIN_C6)//UART1
#define TIMER1_0_3125MS 0xFD8F //Timer1 interrupts 3200/sec
unsigned int8 flag;
#int_timer1
void TIMER1_ISR(){
flag = 121;
set_timer1(TIMER1_0_3125MS); //Load timer1-register to interrupt every 312,5us
}
#INT_DEFAULT
void glob_isr(){
flag=144;
}
void main(){
setup_oscillator(OSC_8MHZ, 0);
set_timer1(TIMER1_0_3125MS); //Set timer1 to interrupt every 312.5us
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //internal clock source and prescale as 1
enable_interrupts(INT_TIMER1); //Enable overflow interrupt Timer1,
enable_interrupts(GLOBAL); //Enable global interrupt
flag = 7;
for(;;)
{
printf("\nTimer: %Ld", get_timer1());
printf("\nFlag: %u", flag);
}
} |
I tested it in the simulator and v4.077 and it works like a charm.
With a software UART and this many interrupts I doubt you were able to get a readable text over the RS232. Is this really the code you used? |
|
|
Jonatan
Joined: 17 Jun 2010 Posts: 5 Location: Stockholm - Sweden
|
|
Posted: Fri Jun 18, 2010 1:49 am |
|
|
The UART code is working without problems. Set_bit() and clear_bit(), etc, are not in use. It's legacy code. The set_shiftreg() etc is necessary for my particular hardware.
My program works in the simulator yes, but not on the HW (I discovered this last night). The UART code somehow works, but the interrupt is never trigged. I myself find the UART code somewhat inconsistent, but that is legacy too (I'm, to my despair, forced to use a big chunk of legacy code as I'm only supposed to do some patchwork to fit in new HW), and it seems to work. Sorry for failing to exclude anything not necessary but that has to do with the way I'm debugging on this particular HW. The strange thing is that all this is supposed to work on older HW built around 16F886. My job is to port it to 16F887 and add some functions.
I will play a little with your a bit more downsized version, thanks! |
|
|
Jonatan
Joined: 17 Jun 2010 Posts: 5 Location: Stockholm - Sweden
|
|
Posted: Fri Jun 18, 2010 2:00 am |
|
|
I tried your version in a new project and found the same behavior. It works perfectly in the simulator but not on the controller. Unfortunately I use Pickit 2. Probably I have to HW debug it with ICD3 or something?
Edit: But thanks for the more sane UART code!
On AVR system using GCC you should have any variables that gets updated in ISRs declared volatile. Is there some similar pitfalls on PIC/CCS? (I already tried volatile at no success). |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Jun 18, 2010 3:35 am |
|
|
I never understood the differences between the PicKit2 and ICD2, but for most chips they suffice both.
Quote: | On AVR system using GCC you should have any variables that gets updated in ISRs declared volatile. Is there some similar pitfalls on PIC/CCS? (I already tried volatile at no success). | Using volatile is good programming practice when sharing variables between main() and ISRs but hardly ever used on the PIC. Because of the simplified architecture design in the PIC16/18 you will be save without using 'volatile' as long as the shared variables are 8 bit only. For larger variables & structs you'll have to temporarily disable interrupts on reading/writing. |
|
|
Jonatan
Joined: 17 Jun 2010 Posts: 5 Location: Stockholm - Sweden
|
|
Posted: Fri Jun 18, 2010 8:05 am |
|
|
I was wrong. The new UART code fail to invert the signal rendering all output to gibberish (after a build all). Now back to the old UART code...
Edit: However, it's the timer 1 interrupt that is bugging me, not the UART. Maybe they depend on each other? |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|