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

Timer3 and fprintf anomalous

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
ibg



Joined: 19 Nov 2003
Posts: 22

View user's profile Send private message

Timer3 and fprintf anomalous
PostPosted: Tue Apr 27, 2004 6:42 am     Reply with quote

Hi again,

I have found a problem printing the data I get (Frequency, pulses, signal strength) when I add the code related with timer3. Before that, all the data were printed rigth.

Code:

// External interruption triggers a timer that overflow after 30 ms
// Inside the timer handler the external interruption is enable and the timer disable
// Note that both EXT2 interruption flag and TMR1 overflow interruption flag must be clear in software

#include <18F452.h>
#device *=16 ADC=10

#define I2C_EXT_ADDR 0x40    // I2C extender address
#define TMR1_OFFSET 47105  // offset = 65536 - (0.03 / (32/19660800)) <- To overflow in 30 ms
#define TMR3_OFFSET 64922  // offset = 65536 - (0.001 / (32/19660800)) <- To overflow in 1 ms

#use DELAY(CLOCK=19660800)

#use fast_io(A)            // Fast method of doing Input/Output
#use fast_io(B)            // The direction register will be set later with the "set_tris_X()" instruction
#use fast_io(C)
#use fast_io(D)

#use rs232(baud=38400, xmit=PIN_C0, stream=DEBUG)
#use I2C (master, sda=PIN_C4, scl=PIN_C3, restart_wdt, fast) // Set the communication for the I2C bus

// I/O ports are mapped in memory (Have a look to the Special Function Register (SFR) of PIC18F452)
#byte PORTA  = 0xF80
#byte PORTB  = 0xF81
#byte PORTC  = 0xF82
#byte PORTD  = 0xF83
#byte PORTE  = 0xF84

// Interruption Control Register
#byte INTCON3 = 0xFF0
// Peripheral Interrupt Request (for TIMER1)
#byte PIR1 = 0xF9E
// Peripheral Interrupt Request (for TIMER3)
#byte PIR2 = 0xFA1

unsigned long timer1_offset;
unsigned long timer3_offset;

unsigned long miliseconds= 0;
unsigned int seconds= 0;
short secs_flag = 0;

short int_flag= 0;
unsigned int32 current_freq;
unsigned long signal_strength= 0;
unsigned long ss_acum= 0;
unsigned long ss_average= 0;
unsigned int pulses= 0;

void init();
unsigned int32 read_frequency();
void i2c_ext_tris_P0(BYTE iValue);
void i2c_ext_tris_P1(BYTE iValue);
BYTE i2c_ext_read_P0();
BYTE i2c_ext_read_P1();


//----------------------------------------------------------------------------------
// This interruption service routine is executed when TD edge goes from H to L
#int_ext2
void ext_isr(void)
{
   disable_interrupts(int_ext2);   // disable ext2 interruption to avoid glitches
   signal_strength= read_adc();
   set_timer1(timer1_offset);      // set timer to be overflow in 30 ms
   bit_clear(PIR1, 0);             // bit 0 -> TMR1 Overflow Interrupt Flag bit
   enable_interrupts(int_timer1);
   int_flag= 1;     
   pulses++;
}

//----------------------------------------------------------------------------------
#int_timer1            //We will have this interruption 30 miliseconds after an external interruption occurs
timer1_isr()
{
   bit_clear(INTCON3, 1);
   enable_interrupts(int_ext2);     // Enable ext2 interruption once we are sure we don't have more glitches
   disable_interrupts(int_timer1);
}

//----------------------------------------------------------------------------------
#int_timer3            //We will have this interruption every milisecond
time3_isr()
{
   miliseconds++;
   if (miliseconds == 1000)
   {
      secs_flag= 1;
      seconds++;
      miliseconds = 0;
   }
   set_timer3(timer3_offset);     
}

//=========================================================================
void main()
{
   init();
   fprintf(DEBUG, "Start...\r\n");
   while (1)
   {
      if (int_flag)
      {
         int_flag= 0;       
         current_freq= read_frequency();
         fprintf(DEBUG, "F= %lu \r\n", current_freq);
         fprintf(DEBUG, "SS= %lu \r\n", signal_strength);
         fprintf(DEBUG, "P= %u \r\n", pulses);   
      }
      if (secs_flag)
      {
         fprintf(DEBUG, "%u ", (unsigned int)seconds);
         secs_flag= 0;
      }     
   }
}

void init()
{
   set_tris_a(0x01);       
   set_tris_b(0x04); // 0000 0100      
   set_tris_c(0x00);      
   set_tris_d(0x00);

   // Timers settings
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
   timer1_offset= TMR1_OFFSET;//TIMER1_OFFSET;   // overflow in 30 ms

   setup_timer_3(T3_INTERNAL | T3_DIV_BY_8);
   timer3_offset= TMR3_OFFSET; //TIMER3_OFFSET;  // overflow in 1 ms   
   set_timer3(timer3_offset);      // set timer to be overflow in 30 ms

   // Set the directions of the I/O pins of the i2c extender
   i2c_ext_tris_P0(0xFF);     // 1111 1111 Set the pins as inputs
   i2c_ext_tris_P1(0xFF);     // 1111 1111 Set the pins as inputs

   // Set the AD converter configuration values
   setup_adc(ADC_CLOCK_INTERNAL); // To ensure a minimum TAD (AD conversion Time) time of 1.6 µs
   setup_port_a(ALL_ANALOG);      // same as 'setup_adc_ports()'
   set_adc_channel(0);            // Channel where the analog signal is coming from

   // Activate interruptions
   ext_int_edge(2, H_TO_L);
   input_b(); // read portB -> the latch is reset
   bit_clear(INTCON3, 1); // ext2 interruption flag is cleared
   enable_interrupts(GLOBAL);   // It allows interruptions to become active
   enable_interrupts(int_ext2); // Enable ext2 interruption
   bit_clear(PIR2, 1);             // bit 1 -> TMR3 Overflow Interrupt Flag bit
   enable_interrupts(int_timer3);
}

// Set the direction for the I/O pins in port0
void i2c_ext_tris_P0(BYTE iValue)
{
   i2c_start();
   i2c_write(I2C_EXT_ADDR | 0);
   i2c_write(0x06);
   i2c_write(iValue);
   i2c_stop();
   delay_ms(5);
}

//Set the direction for the I/O pins in port1
void i2c_ext_tris_P1(BYTE iValue)
{
   i2c_start();
   i2c_write(I2C_EXT_ADDR | 0);
   i2c_write(0x07);
   i2c_write(iValue);
   i2c_stop();
   delay_ms(5);
}

// Read the data coming through pins of port0
BYTE i2c_ext_read_P0()
{
   BYTE uiValue=0;

   i2c_start();
   i2c_write(I2C_EXT_ADDR | 0);
   i2c_write(0x00);
   i2c_start();
   i2c_write(I2C_EXT_ADDR | 1);
   uiValue=i2c_read(0);
   i2c_stop();
   return(uiValue);
}

// Read the data coming through pins of port1
BYTE i2c_ext_read_P1()
{
   BYTE uiValue=0;

   i2c_start();
   i2c_write(I2C_EXT_ADDR | 0);
   i2c_write(0x01);
   i2c_start();
   i2c_write(I2C_EXT_ADDR | 1);
   uiValue=i2c_read(0);
   i2c_stop();
   return(uiValue);
}

// Read the 3 last digits of the frequency
// Such digits are sent from the logger to the receiver
unsigned int32 read_frequency()
{
   unsigned int32 freq= 151000; // Frequency range of the receiver is {151000...151999 Mhz}
   BYTE byte0;
   BYTE byte1;
   BYTE mask= 0x0F;
   unsigned int d2, d1, d0;

   byte0= i2c_ext_read_P0();  // Read from i2c bus extender (PORT 0)
   d0= byte0 & mask;
   d1= byte0 >> 4;
   byte1= i2c_ext_read_P1();  // Read from i2c bus extender (PORT 1)       
   d2= byte1 & mask;
//fprintf(DEBUG, "d2 d1 d0 -> %d %d %d\r\n", d2, d1, d0);
   freq= freq + (unsigned int16)d2*100 + d1*10 + d0;
   return freq;
}
/*EOF*/


Anyone has any idea about why is that? Note that the baudrate of the program I'm using to monitor this is 38400 too. I have not changed it.

Cheers,

Imanol
Ttelmah
Guest







Re: Timer3 and fprintf anomalous
PostPosted: Tue Apr 27, 2004 7:29 am     Reply with quote

ibg wrote:
Hi again,

I have found a problem printing the data I get (Frequency, pulses, signal strength) when I add the code related with timer3. Before that, all the data were printed rigth.

Code:

// External interruption triggers a timer that overflow after 30 ms
// Inside the timer handler the external interruption is enable and the timer disable
// Note that both EXT2 interruption flag and TMR1 overflow interruption flag must be clear in software

#include <18F452.h>
#device *=16 ADC=10

#define I2C_EXT_ADDR 0x40    // I2C extender address
#define TMR1_OFFSET 47105  // offset = 65536 - (0.03 / (32/19660800)) <- To overflow in 30 ms
#define TMR3_OFFSET 64922  // offset = 65536 - (0.001 / (32/19660800)) <- To overflow in 1 ms

#use DELAY(CLOCK=19660800)

#use fast_io(A)            // Fast method of doing Input/Output
#use fast_io(B)            // The direction register will be set later with the "set_tris_X()" instruction
#use fast_io(C)
#use fast_io(D)

#use rs232(baud=38400, xmit=PIN_C0, stream=DEBUG)
#use I2C (master, sda=PIN_C4, scl=PIN_C3, restart_wdt, fast) // Set the communication for the I2C bus

// I/O ports are mapped in memory (Have a look to the Special Function Register (SFR) of PIC18F452)
#byte PORTA  = 0xF80
#byte PORTB  = 0xF81
#byte PORTC  = 0xF82
#byte PORTD  = 0xF83
#byte PORTE  = 0xF84

// Interruption Control Register
#byte INTCON3 = 0xFF0
// Peripheral Interrupt Request (for TIMER1)
#byte PIR1 = 0xF9E
// Peripheral Interrupt Request (for TIMER3)
#byte PIR2 = 0xFA1

unsigned long timer1_offset;
unsigned long timer3_offset;

unsigned long miliseconds= 0;
unsigned int seconds= 0;
short secs_flag = 0;

short int_flag= 0;
unsigned int32 current_freq;
unsigned long signal_strength= 0;
unsigned long ss_acum= 0;
unsigned long ss_average= 0;
unsigned int pulses= 0;

void init();
unsigned int32 read_frequency();
void i2c_ext_tris_P0(BYTE iValue);
void i2c_ext_tris_P1(BYTE iValue);
BYTE i2c_ext_read_P0();
BYTE i2c_ext_read_P1();


//----------------------------------------------------------------------------------
// This interruption service routine is executed when TD edge goes from H to L
#int_ext2
void ext_isr(void)
{
   disable_interrupts(int_ext2);   // disable ext2 interruption to avoid glitches
   signal_strength= read_adc();
   set_timer1(timer1_offset);      // set timer to be overflow in 30 ms
   bit_clear(PIR1, 0);             // bit 0 -> TMR1 Overflow Interrupt Flag bit
   enable_interrupts(int_timer1);
   int_flag= 1;     
   pulses++;
}

//----------------------------------------------------------------------------------
#int_timer1            //We will have this interruption 30 miliseconds after an external interruption occurs
timer1_isr()
{
   bit_clear(INTCON3, 1);
   enable_interrupts(int_ext2);     // Enable ext2 interruption once we are sure we don't have more glitches
   disable_interrupts(int_timer1);
}

//----------------------------------------------------------------------------------
#int_timer3            //We will have this interruption every milisecond
time3_isr()
{
   miliseconds++;
   if (miliseconds == 1000)
   {
      secs_flag= 1;
      seconds++;
      miliseconds = 0;
   }
   set_timer3(timer3_offset);     
}

//=========================================================================
void main()
{
   init();
   fprintf(DEBUG, "Start...\r\n");
   while (1)
   {
      if (int_flag)
      {
         int_flag= 0;       
         current_freq= read_frequency();
         fprintf(DEBUG, "F= %lu \r\n", current_freq);
         fprintf(DEBUG, "SS= %lu \r\n", signal_strength);
         fprintf(DEBUG, "P= %u \r\n", pulses);   
      }
      if (secs_flag)
      {
         fprintf(DEBUG, "%u ", (unsigned int)seconds);
         secs_flag= 0;
      }     
   }
}

void init()
{
   set_tris_a(0x01);       
   set_tris_b(0x04); // 0000 0100      
   set_tris_c(0x00);      
   set_tris_d(0x00);

   // Timers settings
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
   timer1_offset= TMR1_OFFSET;//TIMER1_OFFSET;   // overflow in 30 ms

   setup_timer_3(T3_INTERNAL | T3_DIV_BY_8);
   timer3_offset= TMR3_OFFSET; //TIMER3_OFFSET;  // overflow in 1 ms   
   set_timer3(timer3_offset);      // set timer to be overflow in 30 ms

   // Set the directions of the I/O pins of the i2c extender
   i2c_ext_tris_P0(0xFF);     // 1111 1111 Set the pins as inputs
   i2c_ext_tris_P1(0xFF);     // 1111 1111 Set the pins as inputs

   // Set the AD converter configuration values
   setup_adc(ADC_CLOCK_INTERNAL); // To ensure a minimum TAD (AD conversion Time) time of 1.6 µs
   setup_port_a(ALL_ANALOG);      // same as 'setup_adc_ports()'
   set_adc_channel(0);            // Channel where the analog signal is coming from

   // Activate interruptions
   ext_int_edge(2, H_TO_L);
   input_b(); // read portB -> the latch is reset
   bit_clear(INTCON3, 1); // ext2 interruption flag is cleared
   enable_interrupts(GLOBAL);   // It allows interruptions to become active
   enable_interrupts(int_ext2); // Enable ext2 interruption
   bit_clear(PIR2, 1);             // bit 1 -> TMR3 Overflow Interrupt Flag bit
   enable_interrupts(int_timer3);
}

// Set the direction for the I/O pins in port0
void i2c_ext_tris_P0(BYTE iValue)
{
   i2c_start();
   i2c_write(I2C_EXT_ADDR | 0);
   i2c_write(0x06);
   i2c_write(iValue);
   i2c_stop();
   delay_ms(5);
}

//Set the direction for the I/O pins in port1
void i2c_ext_tris_P1(BYTE iValue)
{
   i2c_start();
   i2c_write(I2C_EXT_ADDR | 0);
   i2c_write(0x07);
   i2c_write(iValue);
   i2c_stop();
   delay_ms(5);
}

// Read the data coming through pins of port0
BYTE i2c_ext_read_P0()
{
   BYTE uiValue=0;

   i2c_start();
   i2c_write(I2C_EXT_ADDR | 0);
   i2c_write(0x00);
   i2c_start();
   i2c_write(I2C_EXT_ADDR | 1);
   uiValue=i2c_read(0);
   i2c_stop();
   return(uiValue);
}

// Read the data coming through pins of port1
BYTE i2c_ext_read_P1()
{
   BYTE uiValue=0;

   i2c_start();
   i2c_write(I2C_EXT_ADDR | 0);
   i2c_write(0x01);
   i2c_start();
   i2c_write(I2C_EXT_ADDR | 1);
   uiValue=i2c_read(0);
   i2c_stop();
   return(uiValue);
}

// Read the 3 last digits of the frequency
// Such digits are sent from the logger to the receiver
unsigned int32 read_frequency()
{
   unsigned int32 freq= 151000; // Frequency range of the receiver is {151000...151999 Mhz}
   BYTE byte0;
   BYTE byte1;
   BYTE mask= 0x0F;
   unsigned int d2, d1, d0;

   byte0= i2c_ext_read_P0();  // Read from i2c bus extender (PORT 0)
   d0= byte0 & mask;
   d1= byte0 >> 4;
   byte1= i2c_ext_read_P1();  // Read from i2c bus extender (PORT 1)       
   d2= byte1 & mask;
//fprintf(DEBUG, "d2 d1 d0 -> %d %d %d\r\n", d2, d1, d0);
   freq= freq + (unsigned int16)d2*100 + d1*10 + d0;
   return freq;
}
/*EOF*/


Anyone has any idea about why is that? Note that the baudrate of the program I'm using to monitor this is 38400 too. I have not changed it.

Cheers,

Imanol


You do not need to clear the interrupt flag in the handler, since CCS does this for you. If you feel you must do this, change the line defining the interrupt call, to include the word 'noclear', which then stops the compiler from doing this. By doing the clear twice, all you are doing is increasing the delay in the interrupt handler (however this is minor)...
Now the reason for your problem, is that you are using the 'soft' serial handler. At 38400bps, the 'bit time', is only 26uSec. At just under 20MHz, this corresponds to about 130 instruction times. Generally for serial handling, the maximum allowable 'error' before comms are lost, is in the order of only about 0.4 bit times _totally_ in the entire character length. If an interrupt is called, there is typically about 20 to 30 instructions 'overhead', followed by the handler itself, and then another 20 instructions for the return. Your code in the timer3 interrupt will involve at least perhaps another 20 instructions. In all, perhaps nearly 20uSec!.
The other interrupts, because they 'depend' on I2C events are presumably just not happening at the same time as your comms, but the timer is.
Basically, either use the hardware UART (that is what it is there for...), or disable your timer interrupts while sending data. You can do this in a 'friendly' way, by making an encapsulated version of putc, something like:
Code:

void putc_noint(int8 chr) {
   disable_interrupts(GLOBAL);
   putc(chr);
   enable_interrupts(GLOBAL);
}


then use printf, as:
printf(putc_noint, .......);

The advantage of this, is that the interrupts are disabled on a 'per character' basis, so that dealing with the interrupt is only delayed for at most about 260uSec.

Best Wishes
ibg



Joined: 19 Nov 2003
Posts: 22

View user's profile Send private message

The variables contain the right data?
PostPosted: Tue Apr 27, 2004 12:00 pm     Reply with quote

Hej,

I must admit I just got the idea about the anomalous behaviour of my fprintf but I got a bit lost with all the timingl stuff :(

Actually the purpose of the data I read (frequency, pulses and signal strenth) is to copy it into a string and send it through the I2C to another PIC. Could I have any problem with that if I keep the timer enable?

Now, I'm printing these data on the screen just to monitor the application and check if everything goes well.

Thanks, gracias, tack, merci, grazie...

ibg ;-)
Ttelmah
Guest







Re: The variables contain the right data?
PostPosted: Tue Apr 27, 2004 3:19 pm     Reply with quote

ibg wrote:
Hej,

I must admit I just got the idea about the anomalous behaviour of my fprintf but I got a bit lost with all the timingl stuff :(

Actually the purpose of the data I read (frequency, pulses and signal strenth) is to copy it into a string and send it through the I2C to another PIC. Could I have any problem with that if I keep the timer enable?

Now, I'm printing these data on the screen just to monitor the application and check if everything goes well.

Thanks, gracias, tack, merci, grazie...

ibg ;-)

There shouldn't be a problem with I2C, since this is a 'synchronous' bus, instead of RS232 being asynchronous. So the master generates a clock, to time everything. Hence delays don't cause problems. If possible use the hardware I2C, which will carry on sending the data while interrupts are being serviced (same comment as using the hardware UART).
You will have to allow for the interrupt response time in the slave though. If you want to send more than a single character, the slave has to interrupt, and handle the data. This takes the same relatively 'long' time mentioned...

Best Wishes
Guest








The putc_noint function works :-)
PostPosted: Wed Apr 28, 2004 3:50 am     Reply with quote

Hej,

Just to inform that the function 'putc_noint' solves all the problems with my printing :-)

I can keep track of my program without seeing bad characters :-)

Thanks once again,

ibg
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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