|
|
View previous topic :: View next topic |
Author |
Message |
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
Timer Interrupt - not working |
Posted: Sat Jul 28, 2012 7:21 am |
|
|
Hi All,
Apologies but I just Cannot figure out why this interrupt timer routine is not working: Code: | /////// MASTER PROGRAM ////////
#include <18F4550.H>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=48000000)
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
#include "flex_lcd_16x1.c"
#define SPI_SS PIN_E2
#define LSB_LATCH_LE_CL3 PIN_B7
#define LSB_LATCH_OE_CL8 PIN_B2
#define SB_LATCH_LE_CL4 PIN_B6
#define SB_LATCH_OE_CL7 PIN_B3
#define MSB_LATCH_LE_CL5 PIN_B5
#define MSB_LATCH_OE_CL6 PIN_B4
//============================
int tic = 0;
long int count_to_use=300;
static long int count=1;
#int_TIMER2
void TIMER2_isr()
{
if (--count==0) {
count=count_to_use;
tic = 1;
}
else {
tic = 2;
}
}
void main()
{
setup_timer_2(T2_DIV_BY_16,256,8);
enable_interrupts(INT_TIMER2);
enable_interrupts(global);
output_high(SPI_SS); // Initial Slave Select to a high level
setup_spi(SPI_MASTER | SPI_MODE_1 | SPI_CLK_DIV_4);
SETUP_ADC_PORTS(NO_ANALOGS);
while(1)
{
if (tic == 1){
tic=0;
output_low(SPI_SS);
spi_write(255);
delay_us(10);
spi_write(255);
delay_us(10);
spi_write(255);
delay_us(10);
output_high(SPI_SS);
delay_ms(1000);
}
else if (tic == 2){
output_low(SPI_SS);
spi_write(10);
delay_us(10);
spi_write(0);
delay_us(10);
spi_write(0);
delay_us(10);
output_high(SPI_SS);
delay_ms(1000);
}
}
} |
The plan is that it should just keep sending the value '10' until the interrupt occurs and then it should send the value 255.
It just keeps sending the value 10??
And altering the 'count_to_use' value up/down makes no difference.
I thought that by just setting a flag in the interrupt rather than doing any work is the correct plan (keep it very small) and then do everything in main.
But I just can't seem to get anything else apart from '10'. 'tic' never seems to be stored as '1'.
Any thoughts, its annoying me now!!!!!!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sat Jul 28, 2012 7:29 am |
|
|
Step back and prove your chip is running at the speed you expect. Your clock fuses are _impossible_.
You have HS selected, without the PLL enabled. This HS oscillator supports 25MHz max.
You can be working at 48MHz, if you have a crystal that is a multiple of 4Mhz, but then you need the PLLx fuse, where 'x' specifies the division to use to reduce the clock to 4Mhz. Also, HS_PLL, instead of HS, and CPUDIV1.
Always check the PIC is actually running, and running at the speed expected, _before_ looking for anything else.....
Best Wishes |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Sat Jul 28, 2012 8:00 am |
|
|
Hi Ttelmah,
On no, I hope not. I looked over lots of datasheets for the fastest PIC available compared to the compiler version I had.
And I thought I had looked into in depth...
Just had another look at the datasheet, and it is not clear...
I am using a 'can oscillator' - IXQO-350 (48MHz). This has its own +5V supply.
Now in the datasheet, it seems that it can be used in the HS mode, as well as the ECIO. the difference is how OSC2 is configured - general I/O or just O. I have used HS mode. But I cannot find anywhere that states the limit for this configuration?? Where does it state 25MHz??
Regarding the PLL - this would jump it up to 96MHz not 48MHz.
Do you agree?
I changed the code and seriously slowed it down, so that count_to_use is now only 5. and it displayed on the screen - so it is working. I got the maths wrong, and need to work out how long the delay is.
Carl
Quote: | An external clock may also be used when the microcontroller
is in HS Oscillator mode. In this case, the
OSC2/CLKO pin is left open (Figure 2-3).
FIGURE 2-3: EXTERNAL CLOCK INPUT
OPERATION (HS OSC
CONFIGURATION)
2.2.3 EXTERNAL CLOCK INPUT |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sat Jul 28, 2012 8:20 am |
|
|
EC is for using an external oscillator.
However you'd get less RF noise, and lower total power consumption, by using a slower oscillator and the PLL internally. It is probably never worth clocking the chip this fast externally....
Also add NOPBADEN to your fuses. PORT B defaults to analog operation.
Best Wishes |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Sat Jul 28, 2012 8:31 am |
|
|
So is what I am doing wrong? or is it allowed?
Can I use a 48MHz canned oscillator in HS mode as shown and explained in figure 2-3 page 26.?
I understand your point about using a lower clock speed and using the PLL - and I am may have to depending on your answer above.
Thanks
Carl |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Sat Jul 28, 2012 9:39 am |
|
|
I use a 4MHz xtal and 2 caps in my 4550 boards. Having a huge stockpile of them from 16C84 days. Using the 4meg xtal allows running at 48MHz as well as using the internal USB peripheral.
Have to think it's cheaper than a 'canned' 48MHz, smaller footprint as well.
hth
jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sat Jul 28, 2012 11:36 am |
|
|
Use EC mode.
You can clock the input from an external source, in HS mode as well, but look at table 28-8. Param1.
In HS mode with an external input, you can only go to 40MHz.
In HS oscillator mode, 25MHz.
EC mode 48MHz.
I'm a bit puzzled on why you want to choose the 4550. It is slower than quite a few other PIC's (64MHz is common now), but it is pointless to try to actually run the external oscillator at this rate.
Best Wishes |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Sat Jul 28, 2012 5:35 pm |
|
|
Thank you both for your replies.
CCS 4.038 only allows up to 48MHz - this is the reason why I didn't go for a 68MHz version.
Thank you for the clarification regarding the speed - I can use a 48MHz canned Oscillator -but need to change the fuse to EC.
Price is not a concern, ease of implementation is more important - and also an extra I/O is available in comparison to the standard Xtal and cap plan.
'Pointless point' - do you mean I can achieve the same thing by using a 4MHz canned oscillator in HSPLL mode and achieve the same speed? you are correct, and I am probably going to utilise this - but at the moment I will continue with the 48MHz canned oscillator in EC mode - it achieves the same thing (appreciating the possible problems that could occur).
Thanks Again
Carl |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Sun Jul 29, 2012 1:11 am |
|
|
Seriously, if you are using 4.038, then it is very likely this is the main problem. This was a 'beta' release at best. When this was available, there were two compilers for download, 4.xxx, and 3.249, with the latter shown as the 'known working' version. You'd need to dismantle the assembler produced 'line by line', and verify fuse settings etc., to have any hope of finding the problems...
The earliest V4 compilers that gave 99% working code are around the late 4.07x versions. Before this the compiler was full of bugs.
Yes, to run the input with a 48MHz clock coming in, requires the EC fuse.
Yes. You can use a 4MHz oscillator, with 'HS_PLL', 'PLL1' & 'CPUDIV1' to run the chip at 48MHz.
There are plenty of chips 'supported' by this compiler that work at 64MHz. 18F66K80, for example.
If you are working through MPLAB, make _sure_ you set this to compile to 'run' mode, not 'debug' mode. Depending on the version, it may well default to the latter, and when this happens, fuses can be set that prevent the chip from running normally.....
Best Wishes |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Fri Aug 03, 2012 3:59 am |
|
|
Hi Ttelmah. Temtronic
OK I decided to take a step back as you pointed out and see if I can get the timer to work - and I did and it worked. The reason why it didn't work was I didn't understand how timer2 worked (the PR2 issue). So I used timer0 and the code below works - it gives the interrpupt I expected, and I tried it with different value and it always worked: Code: | /////// timer test program ////////
#include <18F4550.H>
#fuses EC_IO, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP,NOUSBDIV, NOVREGEN
#use delay(clock=48000000)
#use standard_io(a)
#use standard_io(b)
#use standard_io(c)
#use standard_io(d)
#use standard_io(e)
#define tohex(x) (x & 0xF) < 10 ? x + '0' : x + '7'
#byte UCFG = getenv("SFR:UCFG") //USB Registors
#bit UTRDIS = UCFG.3 //USB Registors
int tic, input_lsb, input_sb, input_msb = 0;
long int count_to_use=300;
static long int count=1;
#include "flex_lcd_16x1.c"
#int_RTCC
void RTCC_isr(void)
{
if (--count==0) {
count=count_to_use;
tic = 1;
}
else {
tic = 2;
}
}
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256);
enable_interrupts(INT_TIMER0);
enable_interrupts(global);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
lcd_init();
while(1)
{
if (tic == 1){ ////////////////////INTERRUPT HAS OCCURRED///////////////////////////
tic=0; //RESET TIMER
printf(lcd_putc,"\f\interrupt");
delay_ms(500);
}
else if (tic == 2){ ////////////////////INTERRUPT HAS NOT OCCURRED///////////////////////////
tic=0;
printf(lcd_putc,"\fNo");
}
}
}
|
So going back to my current project with a new timer set up and I really need your help to see if I am doing anything wrong or the possible cause of the error. The project has been discussed previously in the thread belowhttp://www.ccsinfo.com/forum/viewtopic.php?t=47489&highlight=
It is an absolute test box that takes a snap-shot of the code every 50uS (ideal target), detects if it OK, then send it via SPI to the 2nd PIC. all this occurs in real time. The LCD displays the value now and again on a seperate PIC.
I am utilising three external latches (74HCT573N) to take the snap shot, and if the encoder is turned very slowly (0.5rps), then the code works - No error is detected as the encoder turns (or is stationary) in either CW/CCW direction.
But when the encoder is turned faster, then an error is generated. And the error occurs in different locations - not just one part of the count.
The code is below: Code: | /////// MASTER PROGRAM ////////
///*
#include <18F4550.H>
#fuses EC, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP, NOPBADEN, NOVREGEN
#use delay(clock=48000000)
#use standard_io(a)
#use standard_io(b)
#use standard_io(c)
#use standard_io(d)
#use standard_io(e)
#byte UCFG = getenv("SFR:UCFG") //USB Registors
#bit UTRDIS = UCFG.3 //USB Registors
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
#include "flex_lcd_16x1.c"
#define SPI_SS PIN_E2
#define LSB_LATCH_LE_CL3 PIN_B7
#define LSB_LATCH_OE_CL8 PIN_B2
#define SB_LATCH_LE_CL4 PIN_B6
#define SB_LATCH_OE_CL7 PIN_B3
#define MSB_LATCH_LE_CL5 PIN_B5
#define MSB_LATCH_OE_CL6 PIN_B4
//============================
signed int tic, input_lsb, input_sb, input_msb = 0;
signed long int ans;
int count_to_use=8; // NOT USED FOR NOW
static long int count=1;
signed long int fullbyte_read_current, fullbyte_read_old;
#int_RTCC
void RTCC_isr(void)
{
// if (--count==0) {
// count=count_to_use;
tic = 1; // SET INTERRUPT HAS OCCURRED FLAG
// }
// else {
// tic = 2;
// }
}
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_8); // this should generate a 170.6uS interrupt.
enable_interrupts(INT_TIMER0);
enable_interrupts(global);
output_high(SPI_SS); // Initial Slave Select to a high level
setup_spi(SPI_MASTER | SPI_MODE_1 | SPI_CLK_DIV_4);
SETUP_ADC_PORTS(NO_ANALOGS);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
output_low(LSB_LATCH_LE_CL3); //Disable all latch's
output_high(LSB_LATCH_OE_CL8);
output_low(SB_LATCH_LE_CL4);
output_high(SB_LATCH_OE_CL7);
output_low(MSB_LATCH_LE_CL5);
output_high(MSB_LATCH_OE_CL6);
////////////////////////////////////////INITIAL 24-BIT CATCH (OLD VALUE)//////////////////////////
output_high(LSB_LATCH_LE_CL3); //LSB Latch Enable
output_high(SB_LATCH_LE_CL4); //SB Latch Enable
output_high(MSB_LATCH_LE_CL5); //MSB Latch Enable
delay_us(1);
output_low(LSB_LATCH_OE_CL8); //LSB Latch Output Enable
delay_us(1);
input_lsb = input_d(); //Read LSB Byte
delay_us(1);
output_low(LSB_LATCH_LE_CL3);
output_high(LSB_LATCH_OE_CL8);
delay_us(1);
output_low(SB_LATCH_OE_CL7); //SB Latch Output Enable
delay_us(1);
input_sb = input_d(); //Read SB Byte
delay_us(1);
output_low(SB_LATCH_LE_CL4);
output_high(SB_LATCH_OE_CL7);
delay_us(1);
output_low(MSB_LATCH_OE_CL6); //MSB Latch Output Enable
delay_us(1);
input_msb = input_d(); //Read MSB Byte
delay_us(1);
output_low(MSB_LATCH_LE_CL5);
output_high(MSB_LATCH_OE_CL6);
delay_us(1);
fullbyte_read_old = make32(0, input_msb, input_sb, input_lsb); //Take initial 24-bit Snap-Shot
//////////////////////////////////////////////////////////////////////////////////////////////////
while(1)
{
if (tic == 1){ ////////////////////INTERRUPT HAS OCCURRED - WE NOW HAVE 170.4uS TO DO EVERYTHING BEFORE THE NEXT INTERRUPT///////////////////////////
tic=0; //RESET INTERRUPT FLAG
output_high(LSB_LATCH_LE_CL3); //LSB Latch Enable
output_high(SB_LATCH_LE_CL4); //SB Latch Enable
output_high(MSB_LATCH_LE_CL5); //MSB Latch Enable
delay_us(1); //More than required
output_low(LSB_LATCH_OE_CL8); //LSB Latch Output Enable
delay_us(1); //More than required
input_lsb = input_d(); //Read LSB Byte
delay_us(1); //More than required???
output_low(LSB_LATCH_LE_CL3); //Disable Latch
output_high(LSB_LATCH_OE_CL8);
delay_us(1); //More than required
output_low(SB_LATCH_OE_CL7); //SB Latch Output Enable
delay_us(1); //More than required
input_sb = input_d(); //Read SB Byte
delay_us(1); //More than required???
output_low(SB_LATCH_LE_CL4); //Disable Latch
output_high(SB_LATCH_OE_CL7);
delay_us(1); //More than required
output_low(MSB_LATCH_OE_CL6); //MSB Latch Output Enable
delay_us(1); //More than required
input_msb = input_d(); //Read SB Byte
delay_us(1); //More than required???
output_low(MSB_LATCH_LE_CL5); //Disable Latch
output_high(MSB_LATCH_OE_CL6);
delay_us(1); //More than required
/////////////////////////////////////ERROR DETECTION CODE///////////////////////////////
fullbyte_read_current = make32(0, input_msb, input_sb, input_lsb); //TAKE CURRENT READ
ans = (fullbyte_read_current - fullbyte_read_old); //TAKE ANWAY FORM PREVIOUS READ
fullbyte_read_old = fullbyte_read_current; //OLD = NEW READ
//////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////CHECK IF AN ERROR HAS OCCURRED AND SEND VALUE//////////
if ((( ans >=-1) && (ans <=1)) || (ans == 0)) {
// if (true){
output_low(SPI_SS); // NO ERRORS DETECTED - SEND 24 BIT VALUE TO SLAVE
delay_cycles(7);
spi_write(ans);
delay_cycles(7);
// spi_write(input_sb);
// delay_us(10);
// spi_write(input_msb);
// delay_us(10);
output_high(SPI_SS);
//input_lsb = 0; //RESET
//input_sb = 0;
//input_msb = 0;
delay_cycles(7);
ans = 0;
}
else if (( ans <-1) || (ans >1)){
output_low(SPI_SS); // ERROR DETECTED - SEND ERROR MESSAGE
delay_cycles(7);
spi_write(ans);
delay_cycles(7);
// spi_write(input_sb);
// delay_us(10);
// spi_write(input_msb);
// delay_us(10);
output_high(SPI_SS);
//input_lsb = 0; //RESET
//input_sb = 0;
//input_msb = 0;
delay_ms(1000);}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//else if (tic == 2){ ////////////////////INTERRUPT HAS NOT OCCURRED - DO SOMETHING ELSE///////////////////////////
// tic=0;
// output_low(SPI_SS);
// spi_write(10);
// delay_cycles(7);
// spi_write(0);
// delay_us(10);
// spi_write(0);
// delay_us(10);
// output_high(SPI_SS);
// delay_cycles(7);
// delay_ms(1000);
//}
}
}
|
I have increased the timer time so thst the timer should produce an interrupt every 170us - which leads me onto my first question:
1) Is this enough time to do everything?? I presume its more than enough, when using a 48MHz Osciallator. this gives over 2000 instrcutions untill the interrupt occurs - surely this is enough??
2) Is the code above correct - especially the error detection (make 32 function). So new value - old value = ans. and 'ANS' should only ever be -1 (shown as 255 on the display), 0 or 1 - depending on which way the shaft is turning. And this is what I currently have the code set up to display - just the 'ANS' value. and when rotated very slow - it flickers between 0, 255 and 1 - which is good. But when run faster it errors.
3) The delays I have incorporated in the code - do they look ok? I have tried various values - but it doesn't make any difference really.
4) Is the problem possibly due to erronous reads when I carry out the snap-shot?? noise or a glitch?? I checked with a scope on some of the channels and the signal looks OK - but I would need a logic analyser to be sure - and I dont have that!
Also to note, that for now, assuming the maximum frequency out of the 2^0 on the encoder was 5KHz - this would equate to a change every 200uS - which is more than the interrupt - so no code could be missed.
I really need your help, as I am running out of ideas as too why it is failing. |
|
|
sseidman
Joined: 14 Mar 2005 Posts: 159
|
|
Posted: Fri Aug 03, 2012 5:11 am |
|
|
I find that setting an output high in the ISR and returning it to low when processing is done is a pretty fair way to see if there's enough headroom in my interrupt rate. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19498
|
|
Posted: Fri Aug 03, 2012 5:15 am |
|
|
There are a few things leaping out.
You are making a 32bit value, and then writing this into a 16bit value. A 'signed long int', is a 16 bit value. You need a 'signed int32', or a 'signed long long'.
You can save yourself a few cycles straight away, by taking advantage of unions:
Code: |
typedef struct {
int8 LSB;
int8 NMSB;
int8 MSB;
int8 TOP;
} my_bytes;
union to_int32 {
my_bytes part;
int32 whole;
} data_current, data_old;
//Then you can write to the bytes as:
data_current.part.LSB=input_d();
//and NMSB, then MSB. Clear data_current.part.TOP once at the start of
//the program.
//Then access the whole thing with:
ans=data_current.whole-data_old.whole;
data_old.whole=data_current.whole;
|
This way the bytes are written _directly_ into the bytes of the int32, as they are read. No need to move them later to the right place.
I suspect the big problem is the need to use int32's.....
Best Wishes |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Fri Aug 03, 2012 5:19 am |
|
|
Good point, This is what I have done with 'tic'.
Tic = 1 when Interruopt occurs.
And in main Tic is reset to 0.
But how to check the 'time' it takes to go from '1' to '0' sounds tricky to do. Obvioculy I cannot do it on the LCD. So how would I time this?
I have not used 'debug' before on MPLAB, although I presume you could 'clock it' somehow.
However I still think the concept of 2000 instructions should be sufficient. |
|
|
carl
Joined: 06 Feb 2008 Posts: 240 Location: Chester
|
|
Posted: Fri Aug 03, 2012 5:23 am |
|
|
Thanks Ttelmah for replying,
I will look into it and get back. |
|
|
sseidman
Joined: 14 Mar 2005 Posts: 159
|
|
Posted: Fri Aug 03, 2012 5:25 am |
|
|
Oscilloscope. A key piece of bench gear that everyone beyond novice hobbyist should have. |
|
|
|
|
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
|