Trouble in understanding function inside library

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Trouble in understanding function inside library

3,538 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Sat Apr 04 09:02:33 MST 2015
Hi ,

I'm doing a school project where I am required to use a temperature sensor to printf out the current temperature detected by the sensor. The problem is that the function takes too long , causing an inevitable delay. I wanted to try to edit the function inside the library but I'm not able to understand the code. Was hoping to get some help here.

The function in the library is as follows :

int32_t temp_read (void)
{
    uint8_t state = 0;
    uint32_t t1 = 0;
    uint32_t t2 = 0;
    int i = 0;

    /*
     * T(C) = ( period (us) / scalar ) - 273.15 K
     *
     * 10T(C) = (period (us) / scalar_div10) - 2731 K
     */

    state = GET_TEMP_STATE;

    /* get next state change before measuring time */
    while(GET_TEMP_STATE == state);
    state = !state;

    t1 = getTicks();

    for (i = 0; i < NUM_HALF_PERIODS; i++) {
        while(GET_TEMP_STATE == state);
        state = !state;
    }

    t2 = getTicks();
    if (t2 > t1) {
        t2 = t2-t1;
    }
    else {
        t2 = (0xFFFFFFFF - t1 + 1) + t2;
    }


    return ( (2*1000*t2) / (NUM_HALF_PERIODS*TEMP_SCALAR_DIV10) - 2731 );
}



These are the definitions :

#define TEMP_TS1 0
#define TEMP_TS0 0

#if TEMP_TS1 == 0 && TEMP_TS0 == 0
#define TEMP_SCALAR_DIV10 1
#define NUM_HALF_PERIODS 340
#elif TEMP_TS1 == 0 && TEMP_TS0 == 1
#define TEMP_SCALAR_DIV10 4
#define NUM_HALF_PERIODS 100
#elif TEMP_TS1 == 1 && TEMP_TS0 == 0
#define TEMP_SCALAR_DIV10 16
#define NUM_HALF_PERIODS 32
#elif TEMP_TS1 == 1 && TEMP_TS0 == 1
#define TEMP_SCALAR_DIV10 64
#define NUM_HALF_PERIODS 10
#endif


#define P0_6_STATE ((GPIO_ReadValue(0) & (1 << 6)) != 0)
#define P0_2_STATE ((GPIO_ReadValue(0) & (1 << 2)) != 0)


#ifdef TEMP_USE_P0_6
#define    GET_TEMP_STATE P0_6_STATE
#else
#define    GET_TEMP_STATE P0_2_STATE
#endif



Note that the library does contain other functions as well , so not all the defined terms will be used.

I have also looked at the datasheet ( http://datasheets.maximintegrated.com/en/ds/MAX6576-MAX6577.pdf ) of the temperature sensor , the general descriptions of how it works is :


Quote:


Figure 3 shows a quick-look application circuit for the
MAX6576 using a universal counter measuring period.
TS1 and TS0 are both tied to ground to select a scalar
multiplier of 10μs/°K. The MAX6576 converts the ambient
temperature into a square wave with a period that is
10 times the absolute temperature of the device in μs.
At room temperature, the universal counter will display
approximately 2980μs




I understand the code up to the line "   state = GET_TEMP_STATE; " , I'm lost after that point.

Thank you and sorry for the trouble.
0 Kudos
Reply
23 Replies

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Thu Apr 09 01:52:40 MST 2015

Quote: R2D2

Quote: mngeowcy
But due to the hardwiring of my circuit board , my temperature sensor is only allowed to be connected to P0.2 or P2.5...



There are timers 4 with 2 capture inputs:

CAP0.0 P1[26]
CAP0.1 P1[27]
CAP1.0 P1[18]
CAP1.1 P1[19]
CAP2.0 P0[4]
CAP2.1 P0[5]
CAP3.0 P0[23]
CAP3.1 P0[24]

If you can't use them, you can't use a captured interrupt  :((



Sorry for the long absence. It appears that I really am not able to use the capture interrupt. I went to take some time off to think about it for abit. I'm thinking of using a faster timer to detect the rising edges of the change in state of the temp sensor. I'm planning to use a timer0 that enters the handler every 1us. I would get the current value of the timer everytime it detects a rising edge , doing this twice would and taking the difference of the two values would give me the period. But I do not know how to initialize timer0 and set it to enter the interrupt handler every 1us.
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Mon Apr 06 06:04:06 MST 2015

Quote: mngeowcy
But due to the hardwiring of my circuit board , my temperature sensor is only allowed to be connected to P0.2 or P2.5...



There are timers 4 with 2 capture inputs:

CAP0.0 P1[26]
CAP0.1 P1[27]
CAP1.0 P1[18]
CAP1.1 P1[19]
CAP2.0 P0[4]
CAP2.1 P0[5]
CAP3.0 P0[23]
CAP3.1 P0[24]

If you can't use them, you can't use a captured interrupt  :((

0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Mon Apr 06 05:39:28 MST 2015

Quote: R2D2
[u]Part 2:[/u]

Timer interrupt handler is storing the captured value (period time in µs) and resetting the timer.

volatile int32_t sensor_time;//sensor time
int32_t temperature;//temperature

void TIMER0_IRQHandler(void)
{
 LPC_TIM0->TC =0;//reset timer
 sensor_time = LPC_TIM0->CR0;//store captured time
 uint32_t reg_val;
 reg_val = LPC_TIM0->IR;
 if(reg_val & (1<<4))            //CR0 interrupt
 {
  LPC_TIM0->IR = (1<<4);              //reset interrupt
 }
}


Now the last step to get the temperature is just to calculate it before you print it 

temperature = (sensor_time -2731)/10;
printf("Temperature %d C\n",temperature);



Thanks for the code. But due to the hardwiring of my circuit board , my temperature sensor is only allowed to be connected to P0.2 or P2.5 , both of which do not have the CAP functionality. Is there a way that I could read the pin value and then pass it to P1.26?
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Apr 05 12:21:22 MST 2015
[u]Part 2:[/u]

Timer interrupt handler is storing the captured value (period time in µs) and resetting the timer.

volatile int32_t sensor_time;//sensor time
int32_t temperature;//temperature

void TIMER0_IRQHandler(void)
{
 LPC_TIM0->TC =0;//reset timer
 sensor_time = LPC_TIM0->CR0;//store captured time
 uint32_t reg_val;
 reg_val = LPC_TIM0->IR;
 if(reg_val & (1<<4))            //CR0 interrupt
 {
  LPC_TIM0->IR = (1<<4);              //reset interrupt
 }
}


Now the last step to get the temperature is just to calculate it before you print it 

temperature = (sensor_time -2731)/10;
printf("Temperature %d C\n",temperature);
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Apr 05 12:14:49 MST 2015
[u]Part 1:[/u]

This function is setting P1.26 as capture input. Timer 0 is runnung with default speed (100MHz / 4), so a prescaler of 25 is generating a time base of 1µs. A rising edge is triggering Timer0 interrupt....

//init CAP0.0 / P1.26 to capture with 1µs
void init_Capture(void)
{
 LPC_PINCON->PINSEL3 |= (3<<20);    //Setup P1.26 as CAP0.0
 LPC_TIM0->PR = (25-1);//1 µs at 100MHz/4
//Note: reset values of timer registers are 0, so setting them isn't necessary
 LPC_TIM0->CCR =((1<<0)|(1<<2));   //capture rising edge with interrupt
 LPC_TIM0->TCR = 1;                //start timer
 NVIC_EnableIRQ(TIMER0_IRQn);
}


Unfortunately P2.5 is no capture input, so you have to connect P1.26 to your sensor output...
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Sun Apr 05 12:08:05 MST 2015

Quote: R2D2

Quote: mngeowcy
Am I on the right track ?



Yes, and if you reset the timer inside the interrupt handler, capture register is storing the period time  :)

No subtraction required  :O



Thanks alot! I'll go check it out after class tmr. You've really helped me a great deal.
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Apr 05 12:03:13 MST 2015

Quote: mngeowcy
Am I on the right track ?



Yes, and if you reset the timer inside the interrupt handler, capture register is storing the period time  :)

No subtraction required  :O
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Sun Apr 05 11:57:24 MST 2015

Quote: R2D2

Quote: mngeowcy
Or at least drop a few hints :)



A capture timer is a timer which has a special cature input to trigger an interrupt.

In your case: a rising or falling edge is triggering an interrupt. Meanwhile the timer is running and counting the time between this interrupts. This time is stored in a special register, the capture register.

So this approch can measure the full period of your sensor output. The interrupt is triggered every 3ms and delivering the period time.

If you now want to read the temperature you can just use the last period time and calculate the temperature.

No delay  :)

That should be doable with about 12 lines of code  :O

I'm trying to find a capture sample here at the moment and I think I can post an example in a few minutes  8-)



I think I get what you mean. So this timer counts the period between interrupts concurrently with the program , as such , there is no need for the code to get stuck in a for loop , resulting in no delay. So to code this, all I would have to do is program the interrupt to occur whenever there is a state change. Then inside the interrupt handler I'll just get the current value of the timer. So subtracting the 2 different times at 2 different intervals gives me the period exactly , thus giving me the exact period time of 3ms. Am I on the right track ?
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Apr 05 11:44:49 MST 2015

Quote: mngeowcy
Or at least drop a few hints :)



A capture timer is a timer which has a special cature input to trigger an interrupt.

In your case: a rising or falling edge is triggering an interrupt. Meanwhile the timer is running and counting the time between this interrupts. This time is stored in a special register, the capture register.

So this approch can measure the full period of your sensor output. The interrupt is triggered every 3ms and delivering the period time.

If you now want to read the temperature you can just use the last period time and calculate the temperature.

No delay  :)

That should be doable with about 12 lines of code  :O

I'm trying to find a capture sample here at the moment and I think I can post an example in a few minutes  8-)
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Sun Apr 05 11:29:18 MST 2015

Quote: R2D2

Quote: mngeowcy
For my code, my main clock is 100MHz. But I've divided it by 1000 to make it such that it enters the systick handler every 1ms. The systick handler just increments a global variable msTicks.



And that's the weakness (or at least one weakness) of your code  :(

If you are triggering an interrupt with 1MHz your chip is busy with jumping to that interrupt handler, executing this handler and returning  :((

Therefore it's not useful to use this mechanism for fast counting  :O



Dang , my entire code is written based on that logic. I think it would be too late to change it now. So I guess to only way to reduce the delay of temp_read(); would be to use capture timers? Is it possible for you to give me a brief explanation of what capture timers are and why they would be better for the temp_read() function? Or at least drop a few hints :)
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Apr 05 11:25:21 MST 2015

Quote: mngeowcy
For my code, my main clock is 100MHz. But I've divided it by 1000 to make it such that it enters the systick handler every 1ms. The systick handler just increments a global variable msTicks.



And that's the weakness (or at least one weakness) of your code  :(

If you are triggering an interrupt with 1MHz your chip is busy with jumping to that interrupt handler, executing this handler and returning  :((

Therefore it's not useful to use this mechanism for fast counting  :O
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Sun Apr 05 11:04:17 MST 2015

Quote: R2D2

Quote: mngeowcy
Thanks for your help so far. I feel like I'm very close to optimizing the code. Just one last question. How does the function depend on how long it takes to increment my counter? I'm unable to see any dependance on it.



How does your counter work?

If your time base is 1µs, your counter must be fast enough to count.

If your main clock is 100Mhz, there are 100 cycles to execute code.
That's not much if you try to use SysTick and an interrupt handler for every 1µs :((

So you have to use a faster counter  :)



For my code, my main clock is 100MHz. But I've divided it by 1000 to make it such that it enters the systick handler every 1ms. The systick handler just increments a global variable msTicks. The geticks() function defined inside the temp_read() function just retrieves the current value of msTicks. So if I were to use a faster counter I could always divide my main clock by 1000*1000 to make the code enter the systick handler every 1µs.

What I'm trying to figure out now is exactly which line of code in the temp_read() function depends on the systick timer that I've set. t1=geticks(); just retrieves the value of msTicks. I've also observed that it's mainly the for loop that causes the long delay , I've observed it to be out 500ms. So reducing that delay will ultimately make the function process faster.
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Apr 05 09:09:15 MST 2015

Quote: mngeowcy
Thanks for your help so far. I feel like I'm very close to optimizing the code. Just one last question. How does the function depend on how long it takes to increment my counter? I'm unable to see any dependance on it.



How does your counter work?

If your time base is 1µs, your counter must be fast enough to count.

If your main clock is 100Mhz, there are 100 cycles to execute code.
That's not much if you try to use SysTick and an interrupt handler for every 1µs :((

So you have to use a faster counter  :)
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Sun Apr 05 08:43:47 MST 2015

Quote: R2D2

Quote: mngeowcy
I get this part , so at higher temperatures there will be a longer period which means a longer delay?



At 30°C = 303°K that's 3030µs, just 300µs longer.

The delay is caused because you wait until a new half period is starting before you measure it  :O

So you have a delay somewhere between a half period and a full period  |(

Therefore capture timers are used to measure times in interrupts without waiting for something...



Quote: mngeowcy
Also , the final result returns 10 times the value of the temp , by is the returned value multiplied by another 100 in the function ?



I dont know what the author of this code is trying to do there...
Usually I'm writing my own code and using the features of the chip  :)



Thanks for your help so far. I feel like I'm very close to optimizing the code. Just one last question. How does the function depend on how long it takes to increment my counter? I'm unable to see any dependance on it.
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Apr 05 08:34:12 MST 2015

Quote: mngeowcy
I get this part , so at higher temperatures there will be a longer period which means a longer delay?



At 30°C = 303°K that's 3030µs, just 300µs longer.

The delay is caused because you wait until a new half period is starting before you measure it  :O

So you have a delay somewhere between a half period and a full period  |(

Therefore capture timers are used to measure times in interrupts without waiting for something...



Quote: mngeowcy
Also , the final result returns 10 times the value of the temp , by is the returned value multiplied by another 100 in the function ?



I dont know what the author of this code is trying to do there...
Usually I'm writing my own code and using the features of the chip  :)
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Sun Apr 05 08:17:07 MST 2015

Quote: R2D2

Quote: mngeowcy
getTicks() is just returning the value of a counter that increments every 1ms.



:D

And do you think that's fast enough for your sensor output?


Quote: mngeowcy
Btw how did you know that my sensor is generating a pulse of 3000 µs? Also , will speeding up the clock cause the reading to be more inaccurate ?



Sensor datasheet is talking about output of 10*T in µs (TS1=0, TS0=0)  :O

So at 0°C that should be 273°K * 10µs/°K = 2730 µs, right  :quest:

Not sure what you are trying to measure, but with a 1ms counter your resolution isn't very high...




Quote:
10*T in µs (TS1=0, TS0=0)

What is T referring to here?


Quote:
So at 0°C that should be 273°K * 10µs/°K = 2730 µs



I get this part , so at higher temperatures there will be a longer period which means a longer delay?

Also , the final result returns 10 times the value of the temp , by is the returned value multiplied by another 100 in the function ?
0 Kudos
Reply

3,279 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Apr 05 08:06:51 MST 2015

Quote: mngeowcy
getTicks() is just returning the value of a counter that increments every 1ms.



:D

And do you think that's fast enough for your sensor output?


Quote: mngeowcy
Btw how did you know that my sensor is generating a pulse of 3000 µs? Also , will speeding up the clock cause the reading to be more inaccurate ?



Sensor datasheet is talking about output of 10*T in µs (TS1=0, TS0=0)  :O

So at 0°C that should be 273°K * 10µs/°K = 2730 µs, right  :quest:

Not sure what you are trying to measure, but with a 1ms counter your resolution isn't very high...
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Sun Apr 05 07:51:37 MST 2015

Quote: R2D2

Quote: mngeowcy
I'm still unclear , NUM_HALF_PERIODS doesn't seem to be changing , assuming that pins TS0 and TS1 are fixed connections. I'm still unsure what the for loop is doing. The time base is set to 1milisecond. So my guess is that the for loop estimates the time taken for 340 half periods , and takes the average multiplied by 2 to get the best estimate for 1 period.



I don't know, what 'getTicks()' is doing in detail, but probably it's reading a counter  :quest:

If that counter is counting 1ms ticks, it's of course far too slow  :((

Your sensor is generating a pulse around 3000 µs, with 10us/°K. So your timer should count with a time base of 1µs or 10µs  ;-)


Quote: mngeowcy
Also , I've tried looking through the user guide for a capture timer but couldn't find anything.



User manual:

Quote:

21.6.9 Capture Registers (CR0 - CR1)...



Sample: #9 of http://www.lpcware.com/content/forum/lpc1769-capture-timer

should show, how Capture is working...



getTicks() is just returning the value of a counter that increments every 1ms. Btw how did you know that my sensor is generating a pulse of 3000 µs? Also , will speeding up the clock cause the reading to be more inaccurate ?
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by R2D2 on Sun Apr 05 07:38:47 MST 2015

Quote: mngeowcy
I'm still unclear , NUM_HALF_PERIODS doesn't seem to be changing , assuming that pins TS0 and TS1 are fixed connections. I'm still unsure what the for loop is doing. The time base is set to 1milisecond. So my guess is that the for loop estimates the time taken for 340 half periods , and takes the average multiplied by 2 to get the best estimate for 1 period.



I don't know, what 'getTicks()' is doing in detail, but probably it's reading a counter  :quest:

If that counter is counting 1ms ticks, it's of course far too slow  :((

Your sensor is generating a pulse around 3000 µs, with 10us/°K. So your timer should count with a time base of 1µs or 10µs  ;-)


Quote: mngeowcy
Also , I've tried looking through the user guide for a capture timer but couldn't find anything.



User manual:

Quote:

21.6.9 Capture Registers (CR0 - CR1)...



Sample: #9 of http://www.lpcware.com/content/forum/lpc1769-capture-timer

should show, how Capture is working...
0 Kudos
Reply

3,278 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mngeowcy on Sun Apr 05 07:17:54 MST 2015

Quote: R2D2
I think the author of this code was trying to get a temperature value from his measured pulse time. Probably he was just changing  NUM_HALF_PERIODS until the temperature value was halfway correct  :O
And probably his time base (ticks) had also a different frequency...

Anyway, there are several options to measure a pulse with LPC1769. Of course it's not very elegant to wait until a half period is measured (in this case > 3ms) as in your sample  :((

A better way is to use a capture timer which is generating an interrupt  :)



I'm still unclear , NUM_HALF_PERIODS doesn't seem to be changing , assuming that pins TS0 and TS1 are fixed connections. I'm still unsure what the for loop is doing. The time base is set to 1milisecond. So my guess is that the for loop estimates the time taken for 340 half periods , and takes the average multiplied by 2 to get the best estimate for 1 period.

Also , I've tried looking through the user guide for a capture timer but couldn't find anything.
0 Kudos
Reply