|
|
View previous topic :: View next topic |
Author |
Message |
ibg
Joined: 19 Nov 2003 Posts: 22
|
Timer3 and fprintf anomalous |
Posted: Tue Apr 27, 2004 6:42 am |
|
|
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 |
Posted: Tue Apr 27, 2004 7:29 am |
|
|
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
|
The variables contain the right data? |
Posted: Tue Apr 27, 2004 12:00 pm |
|
|
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? |
Posted: Tue Apr 27, 2004 3:19 pm |
|
|
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 :-) |
Posted: Wed Apr 28, 2004 3:50 am |
|
|
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 |
|
|
|
|
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
|