![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
luis.rigoni
Joined: 14 Oct 2010 Posts: 12
|
usb bootloader and timer0 |
Posted: Fri Oct 29, 2010 3:31 pm |
|
|
Hello, I'm having problems using a USB bootloader and timer0 with PIC18F4550. I have loaded the EX_USB_BOOTLOADER.C the pic.
In my application I'm trying to send a message through USB to the PC containing the read of A/D channel and the interval between the messages of a second.
The code I'm using is:
Code: | #include <18F4550.h>
#DEVICE ADC=10
//configure a 20MHz crystal to operate at 48MHz
#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV1,VREGEN
#use delay(clock=48M)
#include <usb_cdc.h>
#include <usb_bootloader.h>
int conTmr = 0;
long read_analog(int ch) {
set_adc_channel(ch);
delay_us(10);
return read_adc();
}
#int_timer0
void logger() {
int i;
long value;
conTmr++;
if (conTmr >= 11) {
conTmr = 0;
printf(usb_cdc_putc, "\033[2J"); // clean HyperTerminal screen
if (usb_enumerated()) {
printf(usb_cdc_putc, "Time: TODO\r\n");
for(i = 0; i < 2; i++) {
value = read_analog(i);
printf(usb_cdc_putc, "A/D Ch%d = %Ld ", i, value);
}
printf(usb_cdc_putc, "\n\r");
}
}
}
void main() {
usb_cdc_init();
usb_init();
setup_port_a(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_0(RTCC_DIV_16);
set_timer0(0);
enable_interrupts(INT_TIMER0);
while(!usb_cdc_connected()) {}
printf(usb_cdc_putc, "Start Sampling:\n\r");
do {
usb_task();
} while (TRUE);
}
|
Messages received by HyperTerminal is something like this:
Code: | Start Sampling:
2JT222T222 |
Note that these characters are fragments of messages sent by the PIC.
It seems that some other interruption is affecting timer0 interruption.
This same code works correctly if it is loaded without the bootloader.
My compiler is 4.093.
Thanks in advance |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 29, 2010 4:02 pm |
|
|
Do a test. Comment out the Timer0 interrupt routine, and also the lines
that enable interrupts. Move the isr code into a while loop in main().
Put a delay_ms(1000) statement at the end of the while loop. This
emulates your interrupt code, but without any possible problems that
might occur from things being done inside an isr.
I suggest the above as an experiment. |
|
![](templates/subSilver/images/spacer.gif) |
luis.rigoni
Joined: 14 Oct 2010 Posts: 12
|
|
Posted: Fri Oct 29, 2010 4:42 pm |
|
|
PCM programmer wrote: | Comment out the Timer0 interrupt routine, and also the lines that enable interrupts. Move the isr code into a while loop in main(). Put a delay_ms(1000) statement at the end of the while loop. |
I did exactly that and the code worked perfectly using the usb bootloader as a way to load it. Thank PCM. The problem is really the interruption or configuration.
I checked the code several times and can not find why it is not working.
However I would like to use interruption because the firmware in the future will have some more features and delay_ms(1000) no longer represent one second, needing to manually calculate the parameter for each code change.
Can anyone advise me what can I do? |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Oct 29, 2010 4:59 pm |
|
|
Create a global flag variable and initialize it to False.
Use the Timer0 isr, but the only code inside it will be to set the flag = True.
In your while loop in main(), get rid of the delay_ms(1000) and replace
it with an if() statement to check the global flag. If it's true, then set the
flag to False, and execute your loop code. Your loop code will be
executed about once per second. |
|
![](templates/subSilver/images/spacer.gif) |
luis.rigoni
Joined: 14 Oct 2010 Posts: 12
|
|
Posted: Sat Oct 30, 2010 8:55 am |
|
|
PCM programmer wrote: | Create a global flag variable and initialize it to False. Use the Timer0 isr,
but the only code inside it will be to set the flag = True.
In your while loop in main(), get rid of the delay_ms(1000) and replace
it with an if() statement to check the global flag. If it's true, then set the
flag to False, and execute your loop code. Your loop code will be
executed about once per second. |
I declared a global variable int1 flag = false.
Enable timer0 interruption.
Put at the first line of isr flag = true.
And my main loop is:
Code: | do
{
usb_task();
if(flag)
flag = false;
} while (TRUE); |
But the wrong behavior still occurs.
Any advice? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Sat Oct 30, 2010 9:22 am |
|
|
You are missing the critical point in what PCM Programmer said. You need to move the code currently in the interrupt into the main. _All_ the interrupt need contain is the code to set the flag. So your code becomes:
Code: |
int1 Interrupt_fired=FALSE;
#int_timer0
void timer(void) {
Interrupt_fire=TRUE;
}
//Then in the main
void main(void) {
int i;
long value;
usb_cdc_init();
usb_init();
setup_port_a(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_0(RTCC_DIV_16);
set_timer0(0);
enable_interrupts(INT_TIMER0);
while(!usb_cdc_connected()) {}
printf(usb_cdc_putc, "Start Sampling:\n\r");
do {
usb_task();
if(Interrupt_fired) {
Interrupt_fired = FALSE;
if (usb_enumerated) {
conTmr++;
if (conTmr >= 11) {
conTmr = 0;
printf(usb_cdc_putc, "\033[2J"); // clean HyperTerminal screen
printf(usb_cdc_putc, "Time: TODO\r\n");
for(i = 0; i < 2; i++) {
value = read_analog(i);
printf(usb_cdc_putc, "A/D Ch%d = %Ld ", i, value);
}
printf(usb_cdc_putc, "\n\r");
}
}
} while (TRUE);
}
|
No guarantees on the typing.....
Repeat this mantra fifty times _keep interrupt handlers fast_. There are occasions, when this may be broken, but only if you really understand what you are doing, and _not_ when USB is running.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
luis.rigoni
Joined: 14 Oct 2010 Posts: 12
|
|
Posted: Sat Oct 30, 2010 10:26 am |
|
|
Oops! My bad...
Thank Ttelmah and PCM. It worked perfectly!
Now I've learned:
Quote: | [...] _keep interrupt handlers fast_ [...] |
|
|
![](templates/subSilver/images/spacer.gif) |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Thu Oct 27, 2016 5:18 am |
|
|
Ttelmah wrote: | You are missing the critical point in what PCM Programmer said. You need to move the code currently in the interrupt into the main. _All_ the interrupt need contain is the code to set the flag. So your code becomes:
Code: |
int1 Interrupt_fired=FALSE;
#int_timer0
void timer(void) {
Interrupt_fire=TRUE;
}
//Then in the main
void main(void) {
int i;
long value;
usb_cdc_init();
usb_init();
setup_port_a(ALL_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_0(RTCC_DIV_16);
set_timer0(0);
enable_interrupts(INT_TIMER0);
while(!usb_cdc_connected()) {}
printf(usb_cdc_putc, "Start Sampling:\n\r");
do {
usb_task();
if(Interrupt_fired) {
Interrupt_fired = FALSE;
if (usb_enumerated) {
conTmr++;
if (conTmr >= 11) {
conTmr = 0;
printf(usb_cdc_putc, "\033[2J"); // clean HyperTerminal screen
printf(usb_cdc_putc, "Time: TODO\r\n");
for(i = 0; i < 2; i++) {
value = read_analog(i);
printf(usb_cdc_putc, "A/D Ch%d = %Ld ", i, value);
}
printf(usb_cdc_putc, "\n\r");
}
}
} while (TRUE);
}
|
No guarantees on the typing.....
Repeat this mantra fifty times _keep interrupt handlers fast_. There are occasions, when this may be broken, but only if you really understand what you are doing, and _not_ when USB is running.
Best Wishes |
Hello Ttelmah
I have a few questions about your code. I tried your code and it worked perfectly for me. It prints the analog value each second.
Since my clock is 48MHz i did not understand how your code works with 1 second delay. If i change the line to then i get 10Hz frequency. It is too slow.
I read this http://marianlonga.com/pic-timers-with-blinking-led/
So i tried to modify it to my values.
1/48000000= 2,08*e-8 about 20 nanosecond
Each instruction takes 4 clock cycle so i get 80 nanosec.
Don't have any prescaler since i used oscillator(not sure about that but the link says so http://www.microcontrollerboard.com/pic-timer0-tutorial.html )
And timer resolution is 2^16 so i get (2^16)*8*(10^(-9) ) = 524 us
and you counted your conTmr 11 times so it is about 5.5ms
My question is, it is much more smaller than 1sec. On what line did your code limited it? Or is my calculation wrong?
Another question, on the second link,when you use external clock you get much more delay time for same "count" value and resolution decreases. how is that possible? isn't it should be faster and has to have much resolution?
thank you so much.
note: i edited your code and tried to analog read constantly but printing the value with timer. i want to increase the printing frequency. here is the code.
Code: |
#if !defined(__PCH__)
#error USB CDC Library requires PIC18
#endif
#include<18f2550.h>
#device ADC=10
#include <usb_cdc.h>
#fuses HSPLL, NOWDT, PUT, NOLVP,NOMCLR,NOPROTECT,NODEBUG,NOBROWNOUT,CPUDIV1,VREGEN,NOPUT,USBDIV,PLL5
#use delay(clock=48000000)
long value=0;
int conTmr=0;
#int_timer0
void timer(void) {
if (usb_enumerated()) {
conTmr++;
if (conTmr >= 11) {
conTmr = 0;
printf(usb_cdc_putc,"%Ld cm ", value);
}
}
}
//!
//Then in the main
void main(void) {
int i=0;
usb_cdc_init();
usb_init();
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(AN0);
setup_timer_0(RTCC_DIV_16);
set_timer0(0);
enable_interrupts(INT_TIMER0);
// while(!usb_cdc_connected()) {} //when this line is active, the code stops working
printf(usb_cdc_putc, "Start Sampling:\n\r");
while(TRUE){
usb_task();
value = read_adc();
}
}
|
Best Wishes
Doğuhan |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9177 Location: Greensville,Ontario
|
|
Posted: Thu Oct 27, 2016 5:36 am |
|
|
While not about the timer...
this...
setup_adc(ADC_CLOCK_INTERNAL);
is wrong.
Please reread the ADC section of the datasheet, pretty sure you'll find a chart/table tht says 'internal' is for really slow PIC clocks AND while asleep...
Jay |
|
![](templates/subSilver/images/spacer.gif) |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Thu Oct 27, 2016 7:57 am |
|
|
temtronic wrote: | While not about the timer...
this...
setup_adc(ADC_CLOCK_INTERNAL);
is wrong.
Please reread the ADC section of the datasheet, pretty sure you'll find a chart/table tht says 'internal' is for really slow PIC clocks AND while asleep...
Jay |
ok but why it limits the timer0? that line is about adc. so the pic read the data slower i ge that. but it should print according to timer not adc line. it would print the same value until the value changed but it would print after all i think.
and if i want to print a certain data like helloworld, how do i make it to print faster?
i changed the code to this
Code: |
#if !defined(__PCH__)
#error USB CDC Library requires PIC18
#endif
#include<18f2550.h>
#device ADC=10
#include <usb_cdc.h>
#fuses HSPLL, NOWDT, PUT, NOLVP,NOMCLR,NOPROTECT,NODEBUG,NOBROWNOUT,CPUDIV1,VREGEN,NOPUT,USBDIV,PLL5
#use delay(clock=48000000)
int conTmr=0;
#int_timer0
void timer(void) {
if (usb_enumerated()) {
conTmr++;
if (conTmr >= 11) {
conTmr = 0;
printf(usb_cdc_putc,"Hello World!");
}
}
}
//!
//Then in the main
void main(void) {
usb_cdc_init();
usb_init();
setup_timer_0(RTCC_DIV_16);
set_timer0(0);
enable_interrupts(INT_TIMER0);
while(!usb_cdc_connected()) {}
printf(usb_cdc_putc, "Start Sampling:\n\r");
while(TRUE){
usb_task();
}
}
|
it still prints about a second. and there is no adc or internal clock. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Oct 27, 2016 11:14 am |
|
|
Quote: | Each instruction takes 4 clock cycle so i get 80 nanosec.
And timer resolution is 2^16 so i get (2^16)*8*(10^(-9) ) = 524 us |
You said an instruction is 80 ns. Why does your equation above show 8 ns ?
Quote: | Don't have any prescaler since i used oscillator. |
You sure do use a pre-scaler for Timer0. It's this line below:
Quote: | setup_timer_0(RTCC_DIV_16); |
It's easier if you do the calculations using frequency. Don't bother with
the period until the end, if you even need it. So, 48 MHz gives a 12 MHz
instruction clock. The Timer0 interrupt frequency is:
12 MHz / (65536 * 16) = 11.44 Hz
You have a variable as an additional counter (rolls over at 11).
This gives:
11.44 H / 11 = 1.04 Hz
There's your 1 second. |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9177 Location: Greensville,Ontario
|
|
Posted: Thu Oct 27, 2016 3:50 pm |
|
|
Something that will eventually affect you is having a printf() in the ISR.
ISRs must be very small and fast to be effective. This includes but not limited to
never use delays in them
never print in them
never do FP math in them
never do extensive calculations in them
never loop checking a 'status bit'
there may be more that others can add...
Jay |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19382
|
|
Posted: Fri Oct 28, 2016 12:34 am |
|
|
and never enable GLOBAL interrupts in them.
a real 'killer' on the PIC.... |
|
![](templates/subSilver/images/spacer.gif) |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Fri Oct 28, 2016 2:05 am |
|
|
Ttelmah wrote: | and never enable GLOBAL interrupts in them.
a real 'killer' on the PIC.... |
that was the most important thing i have ever learned
thank you all.
you have been very helpful.
Best wishes
Doğuhan |
|
![](templates/subSilver/images/spacer.gif) |
doguhanpala
Joined: 05 Oct 2016 Posts: 120
|
|
Posted: Wed Nov 02, 2016 7:27 am |
|
|
PCM programmer wrote: |
It's easier if you do the calculations using frequency. Don't bother with
the period until the end, if you even need it. So, 48 MHz gives a 12 MHz
instruction clock. The Timer0 interrupt frequency is:
12 MHz / (65536 * 16) = 11.44 Hz
You have a variable as an additional counter (rolls over at 11).
This gives:
11.44 H / 11 = 1.04 Hz
There's your 1 second. |
Hello everyone
I have question about this. If i use timer0 at 16 bits i get 11.44 Hz.
But if i use 8 bits(for same prescaler value) i get
12MHz / (256*16) = 2929,68 Hz
So my output frequency increases. But on the internet it is said that 16bit timers have more resolution.
But with 8 bit, my output frequency is much more. Why doesn't it mean more resolution?
I mean, if want want more than 11 hz i can use 8 bit. and if i want to get 1 hz using 8 bit i can do it too by writing this.
Code: | void timer(void) {
conTmr++;
if (conTmr >= 2929) {
conTmr = 0;
printf(usb_cdc_putc,"Hello World!");
} |
but i cant get more than 11hz with 16bit as i understood. how can i create 1ms delay with 16bit timer if it is possible?
what is the advantage of it? and why 16bit have more resolution? am i misunderstanding the conception of "resolution"?
Best Wishes
Doğuhan |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|