|
|
View previous topic :: View next topic |
Author |
Message |
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
Is there a solution for this code crash? |
Posted: Wed Nov 21, 2018 2:24 pm |
|
|
Hello again,
I have this code, I'm writing some things on OLED screen via i2c in main loop but I also use int_ext2. There is some i2c readings in interrupt routine from another device and system crashes if i use external interrupt so much. My guess is that external interrupt kicks in before completing i2c writings and starts i2c readings and i2c bus collision is occurring. So I disabled interrupts while writing to oled and it solved the problem. What I wonder is if there is a better way to solve it without disabling interrupts?
18lf2550 v5.070
It is a long code so I paste only related parts.
Main loop Oled codes which runs every 1 seconds : Code: | if((ScreenPower==1)&&(SMinutes<1))
{
disable_interrupts(GLOBAL);
OLED_gotoxy(0,0);
printf(OLED_putc,"%02u",Hours);
OLED_gotoxy(2,0);
OLED_text(text1,strlen(text1));
OLED_gotoxy(3,0);
printf(OLED_putc,"%02u",Minutes);
OLED_gotoxy(5,0);
OLED_text(text1,strlen(text1));
OLED_gotoxy(6,0);
printf(OLED_putc,"%02u",Seconds);
OLED_gotoxy(0,1);
OLED_text(text2,strlen(text2));
OLED_gotoxy(13,1);
printf(OLED_putc,"%05Lu",SensorCount);
OLED_gotoxy(0,2);
printf(OLED_putc,"%02u",Rtc_Time_Values[4]);
OLED_gotoxy(2,2);
OLED_text(text1,strlen(text1));
OLED_gotoxy(3,2);
printf(OLED_putc,"%02u",Rtc_Time_Values[3]);
OLED_gotoxy(5,2);
OLED_text(text1,strlen(text1));
OLED_gotoxy(6,2);
printf(OLED_putc,"%02u",Rtc_Time_Values[2]);
OLED_gotoxy(8,2);
OLED_text(text1,strlen(text1));
OLED_gotoxy(9,2);
printf(OLED_putc,"%02u",Rtc_Time_Values[1]);
OLED_gotoxy(11,2);
OLED_text(text1,strlen(text1));
OLED_gotoxy(12,2);
printf(OLED_putc,"%02u",Rtc_Time_Values[0]);
OLED_gotoxy(0,3);
printf(OLED_putc,"%02u",ConStatus);
Oled_gotoxy(0,4);
OLED_text(EspRcvBuff,strlen(EspRcvBuff));
OLED_gotoxy(19,7);
if(ErrorCode!=0)
{
printf(OLED_putc,"%02u",ErrorCode);
}
else
{
OLED_text(textNoError,strlen(textNoError));
}
enable_interrupts(GLOBAL);
} |
and this is ext_int2 codes : Code: | #int_EXT2
void EXT2_isr()
{
RtcReadTime();
ext2DropTime=(Rtc_Time_Values[0]+(Rtc_Time_Values[1]*100)+(Rtc_Time_Values[2]*10000)+(Rtc_Time_Values[3]*1000000)+(Rtc_Time_Values[4]*100000000));
if ((ext2DropTime-ext2LastDropTime)<7)
{
delay_cycles(1);
}
else
{
ext2DropInterval=ext2DropTime-ext2LastDropTime;
ext2DropCount++;
ext2TotalDropVolume+=ext2DropVolumeCalculator(ext2DropInterval);
ext2LastDropTime=ext2DropTime;
}
SensorCount++;
} | where RtcReadTime(); does i2c readings. _________________ There is nothing you can't do if you try |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Nov 21, 2018 4:36 pm |
|
|
Quote: | ext2DropTime=(Rtc_Time_Values[0]+(Rtc_Time_Values[1]*100)+(Rtc_Time_Values[2]*10000)+(Rtc_Time_Values[3]*1000000)+(Rtc_Time_Values[4]*100000000));
if ((ext2DropTime-ext2LastDropTime)<7) |
What is the time interval in the above code ? I can't tell from the calculation.
Is it in seconds ?
Also, what causes the external interrupt ? And at what time interval ? |
|
|
Jerson
Joined: 31 Jul 2009 Posts: 125 Location: Bombay, India
|
|
Posted: Wed Nov 21, 2018 7:00 pm |
|
|
I would avoid calling any functions inside the ISR. RTCReadTime itself could be causing problems if the device doesn't like too frequent queries. What is the ISR execution Rate - every second or lesser? |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Thu Nov 22, 2018 6:03 am |
|
|
PCM programmer wrote: | Quote: | ext2DropTime=(Rtc_Time_Values[0]+(Rtc_Time_Values[1]*100)+(Rtc_Time_Values[2]*10000)+(Rtc_Time_Values[3]*1000000)+(Rtc_Time_Values[4]*100000000));
if ((ext2DropTime-ext2LastDropTime)<7) |
What is the time interval in the above code ? I can't tell from the calculation.
Is it in seconds ?
Also, what causes the external interrupt ? And at what time interval ? |
Rtc_Time_Values 0,1,2,3,4 presents tenth miliseconds,seconds,mins,hours and days. These lines are to omit any interrupt happens before 70 miliseconds after first one.
Clock speed is 8MHz internal and 400KHz I2C speed by the way.
External interrupts are triggered by a photointerrupter, intervals changes from miliseconds to hours but fastest interval would be 100-150 miliseconds _________________ There is nothing you can't do if you try
Last edited by elcrcp on Thu Nov 22, 2018 6:17 am; edited 1 time in total |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Thu Nov 22, 2018 6:17 am |
|
|
Jerson wrote: | I would avoid calling any functions inside the ISR. |
Well I have to, because ext_int occuring moment is the exact time I need to know. I normally use flags to avoid doing long calculations or calling functions in ISRs but it has to be done here =)
Jerson wrote: | What is the ISR execution Rate - every second or lesser? |
it changes from miliseconds to hours but maximum rate would be 100-150 miliseconds or maybe 200
I use 8MHz clock speed and 400KHz I2C speed _________________ There is nothing you can't do if you try |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu Nov 22, 2018 7:13 am |
|
|
Quote: |
it has to be done here
|
No it doesn't....
Keep time in the PIC. Don't read the RTC in this interrupt. A simple timer 'tick',
can give you time, which even using the internal clock will not drift much. I do
this, and every hour' (by this), read the RTC once and re-sync. That way your
int_ext only needs to record the time, and doesn't have to be trying to read the
RTC. Your interrupt can just record the count on the timer, or the value from
this internal time.
This way two triggers can be really close together, and cause no problems.
Also, since you don't then use the I2C in the interrupt, you can leave interrupts
enabled while talking to the OLED, which will improve the accuracy of the time
recorded.
Also by multiplying up the RTC time inside the interrupt, you are using a
huge amount of time. int32 arithmetic several times. several hundred
thousand machine cycles.... :(
Your issue is occurring, because I2C operations require a complete 'set'
of actions. The compiler automatically protects the parts, but not the
'set'. So you talk to a device with a start, address, data, stop. The
components of this are each protected from being interrupted, but once
the bus is 'open' (the start has been sent), if an interrupt occurs the bus
is already in use when the code in the interrupt happens. You could
disable on a 'per transaction' basic.
Your transactions are actually very inefficiently done. Much better to
assemble a complete string contining the hours, mins, seconds, and send
this as one operation, instead of sending locations for each character/pair
of characters. |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Thu Nov 22, 2018 5:18 pm |
|
|
All right, I made some changes but I haven't tried it on device yet. My RTC has 10 milliseconds resolution and so I setup timer3 same to follow RTC and added some lines to main loop to align RTC and TMR3 every hour. Here is main loop : Code: | while(TRUE)
{
.
.
.
.
if((ScreenPower==1)&&(SMinutes<1))
{
OLED_gotoxy(0,0);
printf(OLED_putc,"%02u",Hours);
OLED_gotoxy(2,0);
OLED_text(text1,strlen(text1));
OLED_gotoxy(3,0);
printf(OLED_putc,"%02u",Minutes);
OLED_gotoxy(5,0);
OLED_text(text1,strlen(text1));
OLED_gotoxy(6,0);
printf(OLED_putc,"%02u",Seconds);
OLED_gotoxy(0,1);
OLED_text(text2,strlen(text2));
OLED_gotoxy(13,1);
printf(OLED_putc,"%05Lu",SensorCount);
OLED_gotoxy(0,2);
printf(OLED_putc,"%02u",TMR3_Time_Values[4]);
OLED_gotoxy(2,2);
OLED_text(text1,strlen(text1));
OLED_gotoxy(3,2);
printf(OLED_putc,"%02u",TMR3_Time_Values[3]);
OLED_gotoxy(5,2);
OLED_text(text1,strlen(text1));
OLED_gotoxy(6,2);
printf(OLED_putc,"%02u",TMR3_Time_Values[2]);
OLED_gotoxy(8,2);
OLED_text(text1,strlen(text1));
OLED_gotoxy(9,2);
printf(OLED_putc,"%02u",TMR3_Time_Values[1]);
OLED_gotoxy(11,2);
OLED_text(text1,strlen(text1));
OLED_gotoxy(12,2);
printf(OLED_putc,"%02u",TMR3_Time_Values[0]);
OLED_gotoxy(0,3);
printf(OLED_putc,"%02u",ConStatus);
Oled_gotoxy(0,4);
OLED_text(EspRcvBuff,strlen(EspRcvBuff));
OLED_gotoxy(19,7);
if(ErrorCode!=0)
{
printf(OLED_putc,"%02u",ErrorCode);
}
else
{
OLED_text(textNoError,strlen(textNoError));
}
}
.
.
.
.
if(Hours!=HoursLast)
{
if(!RTC_Read_Done)
{
disable_interrupts(GLOBAL);
RtcReadTime();
TMR3_Time_Values[0]=Rtc_Time_Values[0];
TMR3_Time_Values[1]=Rtc_Time_Values[1];
TMR3_Time_Values[2]=Rtc_Time_Values[2];
TMR3_Time_Values[3]=Rtc_Time_Values[3];
TMR3_Time_Values[4]=Rtc_Time_Values[4];
enable_interrupts(GLOBAL);
RTC_Read_Done=1;
}
else
{
EspSendHourlyData();
}
}
.
.
.
. |
I used enable/disable interrupt at TMR and RTC aligning lines because I want that job done as fast as can without interrupted.
and I also changed ext2 ISR so it won't read RTC.
Plus, my time data form is dd:hh:mm:ss:uu and their max values are 31:23:59:59:99 so I used shifts instead of multiplication considering their max values and I thing it will relive a lot of cycles XD.
Code: | #int_EXT2
void EXT2_isr()
{
ext2DropTime=(TMR3_Time_Values[0]+(TMR3_Time_Values[1]<<7)+(TMR3_Time_Values[2]<<13)+(TMR3_Time_Values[3]<<19)+(TMR3_Time_Values[4]<<24));
if ((ext2DropTime-ext2LastDropTime)<7)
{
delay_cycles(1);
}
else
{
ext2DropInterval=ext2DropTime-ext2LastDropTime;
ext2DropCount++;
ext2TotalDropVolume+=ext2DropVolumeCalculator(ext2DropInterval);
ext2LastDropTime=ext2DropTime;
}
SensorCount++;
} |
_________________ There is nothing you can't do if you try |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Nov 23, 2018 2:23 am |
|
|
Code: |
ext2DropTime=(TMR3_Time_Values[0]+(TMR3_Time_Values[1]<<7)+(TMR3_Time_Values[2]<<13)+(TMR3_Time_Values[3]<<19)+(TMR3_Time_Values[4]<<24));
|
Probably won't work.
Reason is 'size'.
Assume TMR3_Time_values, is int8?.
Then you can't shift it left 7, 13, 19 or 24 bits, since the variable is not large enough to take the result.
The only reason it worked with the multiplication, was implicit casting. If you multiplied an int8, by 10000 (say), the compiler sees that this multiplicand is a 16bit value, and implicitly casts the value up to the larger type. For your shifts, this doesn't happen.
You'd need to explicitly cast up. So:
Code: |
ext2DropTime=(TMR3_Time_Values[0]+((int16)TMR3_Time_Values[1]<<7)+((int32)TMR3_Time_Values[2]<<13)+((int32)TMR3_Time_Values[3]<<19)+((int32)TMR3_Time_Values[4]<<24));
|
However I'd honestly still say, why not just have a tick, stored in an int32?. The tests then become a doddle, so do the conversions here etc.. You can convert this 'tick' back and forth to the separate bytes form very easily when you read or write the RTC. In CPU terms working with a 'tick' value is a much nicer way to go. |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Fri Nov 23, 2018 5:25 am |
|
|
Ttemah wrote: | However I'd honestly still say, why not just have a tick | I think you mean "#USE TIMER" funciton? I checked it after you mentioned but there is no start/stop command for that function. However I believe I can control it by controlling releated timer on/off bit. I just don't get how that function increases tick counts without using an ISR? I mean, there is a timer counting in background and there is a variable to write that ticks to. When and where it writes in that variable if its not interrupting the program flow? _________________ There is nothing you can't do if you try |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Fri Nov 23, 2018 5:31 am |
|
|
No, I just meant use a tick.
Just have a counter. When you read the time from the RTC, turn this into a count from an arbitrary point in time you have chosen. Load the counter with this. Then just have an interrupt tick called every 10mSec, that increments this.
In your edge interrupt code, storing the time, just becomes a matter of saving the count in this. Nothing more.
If you want to display this, just use simple division to give the 'clock' time.
I quite commonly use 'mSec in the day' as a tick value (since then I don't have to calculate the day times, since these don't change all day).
#use timer, is a CCS 'complication', to try to make using a timer simpler.... However if you choose your timer with care, the chip can make it simpler for you. So (for example), in your case if you are not using timer2, this using /16 prescaler, PR2=124, and postscale /10, gives 100 interrupts/second. |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Fri Nov 23, 2018 5:20 pm |
|
|
Oh, I see now. So you say, instead of doing tests and increase seconds,minutes etc. in timer isr and then merging them together in every ext2 isr, just use a mseconds counter in timer isr and use that value in ext2 isr and only convert them to seconds, minutes, etc. when I show or send them. This is indeed much efficient.
I think my thinking is stuck at dd:hh:mm:ss:uu format because of RTC data format and couldn't understand what you are trying to say.
Thank you! _________________ There is nothing you can't do if you try |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Sat Nov 24, 2018 2:01 am |
|
|
Exactly.
And (of course), the key is that the 'efficiency' is exactly where you need it (in
the ISR). Delays for the conversions only occur out in the display code.
RTC chips are generically 'designed' for things like 'clocks', where output is in
'human readable' form. C has a standard library (time.c/time.h), which
converts a 'tick', backwards and forwards to a human readable form. You have
to define 'CLOCK_PER_SECOND' to tell it what the 'tick' rate actually is, and the
functions in this can then handle all the conversions. |
|
|
|
|
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
|