CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

usb bootloader and timer0
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
luis.rigoni



Joined: 14 Oct 2010
Posts: 12

View user's profile Send private message

usb bootloader and timer0
PostPosted: Fri Oct 29, 2010 3:31 pm     Reply with quote

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
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 29, 2010 4:02 pm     Reply with quote

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.
luis.rigoni



Joined: 14 Oct 2010
Posts: 12

View user's profile Send private message

PostPosted: Fri Oct 29, 2010 4:42 pm     Reply with quote

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?
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Oct 29, 2010 4:59 pm     Reply with quote

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.
luis.rigoni



Joined: 14 Oct 2010
Posts: 12

View user's profile Send private message

PostPosted: Sat Oct 30, 2010 8:55 am     Reply with quote

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?
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Sat Oct 30, 2010 9:22 am     Reply with quote

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
luis.rigoni



Joined: 14 Oct 2010
Posts: 12

View user's profile Send private message

PostPosted: Sat Oct 30, 2010 10:26 am     Reply with quote

Oops! My bad...

Thank Ttelmah and PCM. It worked perfectly!

Now I've learned:

Quote:
[...] _keep interrupt handlers fast_ [...]
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

PostPosted: Thu Oct 27, 2016 5:18 am     Reply with quote

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
Code:
if (conTmr >= 11)
to
Code:
if (conTmr >= 1)
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
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Oct 27, 2016 5:36 am     Reply with quote

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
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

PostPosted: Thu Oct 27, 2016 7:57 am     Reply with quote

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.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Oct 27, 2016 11:14 am     Reply with quote

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.
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Oct 27, 2016 3:50 pm     Reply with quote

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
Ttelmah



Joined: 11 Mar 2010
Posts: 19538

View user's profile Send private message

PostPosted: Fri Oct 28, 2016 12:34 am     Reply with quote

and never enable GLOBAL interrupts in them. Smile

a real 'killer' on the PIC....
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

PostPosted: Fri Oct 28, 2016 2:05 am     Reply with quote

Ttelmah wrote:
and never enable GLOBAL interrupts in them. Smile

a real 'killer' on the PIC....


that was the most important thing i have ever learned Smile

thank you all.

you have been very helpful.

Best wishes

Doğuhan
doguhanpala



Joined: 05 Oct 2016
Posts: 120

View user's profile Send private message

PostPosted: Wed Nov 02, 2016 7:27 am     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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