flek12345 0 Posted November 21, 2014 Share Posted November 21, 2014 I am using Tiva. TM4C123GXL. On a pin F4, there is connected external device which generates pulse (HC-SR04). I want to measure that pulse width. My idea is: When pulse arrives (transition high-to-low), I will start a timer. And it will count down. I know that maximal pulse width is 23 milliseconds (so I put 100 ms in timer). When pulse is over (transition low-to-high), I will read timer value. Defeerence between those 2 ticks, I will multiply by system frequency (50 MHz). And it will be my pulse width. Right? But, whatever I do, I got pulse width equal to 99 milliseconds. (With logic analizer, I see that pulse width is 0.84 milliseconds) What am I doing wrong? This is my code. Initialization for PF4: // F4 (input, interrupt driven) GPIO_PORTF_DIR_R &= ~0x10; // (c) make PF4 in (built-in button) GPIO_PORTF_AFSEL_R &= ~0x10; // disable alt funct on PF4 GPIO_PORTF_DEN_R |= 0x10; // enable digital I/O on PF4 GPIO_PORTF_PCTL_R &= ~0x000F0000; // configure PF4 as GPIO GPIO_PORTF_AMSEL_R = 0; // disable analog functionality on PF GPIO_PORTF_PUR_R |= 0x10; // enable weak pull-up on PF4 GPIO_PORTF_IS_R &= ~0x10; // (d) PF4 is edge-sensitive GPIO_PORTF_IBE_R |= 0x10; // PF4 is on both edges GPIO_PORTF_IEV_R &= ~0x10; // PF4 edge event is irelevant GPIO_PORTF_ICR_R = 0x10; // (e) clear flag4 GPIO_PORTF_IM_R |= 0x10; // (f) arm interrupt on PF4 *** No IME bit as mentioned in Book *** NVIC_PRI7_R = (NVIC_PRI7_R&0xFF00FFFF)|0x00A00000; // (g) priority 5 NVIC_EN0_R |= 0x40000000; // (h) enable interrupt 30 in NVIC EnableInterrupts(); // (i) Clears the I bit Timer initialization: SYSCTL_RCGCTIMER_R |= 0x01; // 0) activate timer0 delay = SYSCTL_RCGCTIMER_R; TIMER0_CTL_R = 0x00000000; // 1) disable timer2A during setup TIMER0_CFG_R = 0x00000000; // 2) configure for 32-bit mode TIMER0_TAMR_R = 0x00000002; // 3) configure for periodic mode, default down-count settings TIMER0_TAILR_R = 4999999; // 4) reload value TIMER0_TAPR_R = 0; // 5) bus clock resolution TIMER0_ICR_R = 0x00000001; // 6) clear timer2A timeout flag TIMER0_IMR_R = 0x00000001; // 7) arm timeout interrupt NVIC_PRI4_R = (NVIC_PRI4_R&0x00FFFFFF)|0x80000000; // 8) priority 4 // interrupts enabled in the main program after all devices initialized // vector number 39, interrupt number 23 NVIC_EN0_R = 1<<19; // 9) enable IRQ 23 in NVIC //TIMER0_CTL_R = 0x00000001; // 10) enable timer0A Interrupt service routine if(GPIO_PORTF_RIS_R & 0x10) // poll PF4 { GPIO_PORTF_ICR_R = 0x10; // acknowledge flag for PF4 if (GPIO_PORTF_DATA_R & 0x10) // rising edge { endTick = TIMER0_TAR_R; // read current timer value (end) TIMER0_CTL_R &= ~0x00000001; // stop timer } else // falling edge { TIMER0_TAILR_R = 4999999; // prepare new 100 ms interval TIMER0_CTL_R |= 0x00000001; // enable startTick = TIMER0_TAR_R; // read current timer value (start) } } Function for calculating distance deltaTick = startTick - endTick; time = deltaTick * 0.00000002; Quote Link to post Share on other sites
L.R.A 78 Posted November 21, 2014 Share Posted November 21, 2014 Hi, I don't have time to analyze the code (sorry) But here is how i use that sensor with the launchpad https://sites.google.com/site/luiselectronicprojects/tutorials/tiva-tutorials/tiva-general-purpose-timers/timer-periodic-mode---srf04 Quote Link to post Share on other sites
GrumpyOldPizza 15 Posted November 21, 2014 Share Posted November 21, 2014 I had posted some bare metal code here to do exactly what you are doing with a HC-SR04: http://forum.stellarisiti.com/topic/2027-hc-sr04-ultrasonic-sensor-bare-metal/. So you might want to take a peek there. - Thomas Quote Link to post Share on other sites
igor 163 Posted November 21, 2014 Share Posted November 21, 2014 What am I doing wrong? Using raw register writes instead of library functions? (makes code harder to read). The comments do not match the code (e.g. talks about Timer 2A, but appears to be operating on Timer0?) "If the code and the comments disagree, both are probably wrong." attributed to Norm Schryer Have you checked what value startTick is getting? (i.e. that the timer has had time to reset before you read TIMER0_TAR_R in the interrupt handler) Some devices require a bit of time to start operating (e.g. require adding instructions between writing and reading). Are all the pulses the same length? Quote Link to post Share on other sites
GrumpyOldPizza 15 Posted November 21, 2014 Share Posted November 21, 2014 Using raw register writes instead of library functions? (makes code harder to read). I beg to differ there. Unless you just set up GPIOs using the library functions are a PITA. You never know what registers are actually touched in what sequence. There are so many undocumented side effects. Usually I spend more time reading the driverlib source to figure out what is really done by what function, that it would have taken me just write write direct register accesses. Hence the idea of "makes code easier to read" is at least for me quite the opposite. - Thomas Quote Link to post Share on other sites
flek12345 0 Posted November 24, 2014 Author Share Posted November 24, 2014 @L.R.A. I will take a look at your code. @@igor I am new with Tiva... So, where can I find those library? Although, for my project (HC-SR04), whole code has less than 100 lines.... Concerning "The comments do not match the code (e.g. talks about Timer 2A, but appears to be operating on Timer0?)" Yes. You are right. I copied code from my old project where I used timer2. I will add some (us) delay between timer reset and reading it's value. Generaly, pulses will not be the same. I want to measure any distance. @@BizzaBoy I read your post before (when I was googling HC-SR04). I do not understand part related to WTIMER3AB. And I wanted my system even simpler: Single sensor. Trigger pulse once per second. Interrupt on both edges. Calculate distance based on timer readouts. Quote Link to post Share on other sites
GrumpyOldPizza 15 Posted November 24, 2014 Share Posted November 24, 2014 @@BizzaBoy I read your post before (when I was googling HC-SR04). I do not understand part related to WTIMER3AB. And I wanted my system even simpler: Single sensor. Trigger pulse once per second. Interrupt on both edges. Calculate distance based on timer readouts. Good questions. The setup is a tad more complicated than what you may need. The code is using TIMER2 to provide a 20Hz lm4f120_timer2a_interrupt() interrupt. There are 2 HC-SR04 in my system. One has it's trigger on PE2 and one on PE3. The trigger fires on a falling edge. So this code interleaves the 2 HC-SR04, whereby each HC-SR04 gets a 50ms timeslot. Then WTIMER3AB is setup up to be capture/compare on both edges. This is via PD2/PD3. So I got a trigger for my left HC-SR04 on PE2, and the return pulse on PD2. The right HC-SR04 is triggered via PE3 and the return pulse is on PD3. Now there are 2 interrupt handlers for WTIMER3 (WTIMER3A on PD2, WTIMER3B on PD3), one for the left HC-SR04 and one for the right HC-SR04. Let's look at lm4f120_wtimer3a_interrupt(), which deals with the left HC-SR04. It first checkd PE2. If that is 0, then there was a trigger pulse active. If it's one, the pulse seen on PD2 was random noise. Now PD2 is checked. If that is 1, then there was a 0 -> 1 edge, which means that start of the return pulse. If it is 0, it's a 1 -> 0 edge, hence the end of the return pulse. So on a start of the pulse, the 32bit timer values is stored away in lm4f120_sonar_left_time, and the end of the pulse the delta time is calculated. I am using 32 bit timers, because the maximum return pulse is 38ms and since the timers are driven by the core clock (80MHz), the capture/compare should not overlow the timer, which means it needs about 22 bits. Seemed easier to do that with a 32bit timer than with a 16 bit timer and messing with the prescaler. Anyway, at the end you have lm4f120_sonar_left_pulse which is either 0 if there was no echo, or the number of clock ticks the pulse was in core clock units. In my real system, this was used in a tad more complex way. First off, the interrupt handler would send the data to a task that would process it. It would actually look at the start and end time for the pulse. With a 38ms maximum echo, the rover I used this for would travel about 20cm. Thus the time the sound travels does not represent to true distance at the point in time when the sound pulse was triggered. But I guess that is somewhat esoteric ;-) For the simpler case you are after you could use half of the logic, PD2/PE2, use only WTIMER3A to count, and setup the TIMER2 interrupt to be 2Hz, and toggle only PE2. Quote Link to post Share on other sites
igor 163 Posted November 25, 2014 Share Posted November 25, 2014 @@igor I am new with Tiva... So, where can I find those library? Although, for my project (HC-SR04), whole code has less than 100 lines.... Concerning "The comments do not match the code (e.g. talks about Timer 2A, but appears to be operating on Timer0?)" Yes. You are right. I copied code from my old project where I used timer2. I will add some (us) delay between timer reset and reading it's value. Generaly, pulses will not be the same. I want to measure any distance. As far as the delay between timer set and read - I would check what the data sheet says, and/or check what results you are getting (i.e. when you read the timer, what is the actual result - is it what you expect (close to 4999999)). If it is what expect, and the data sheet doesn't say you need a delay, then don't bother. (I couldn't say in this case whether one is needed or not, checking to be sure that startTick had the expected value was my point.) As far as libraries - http://www.ti.com/tool/sw-tm4c Even if you don't use the libraries in your code, can also be a handy source for examples. (Sometimes the datasheet doesn't tell you everything you need to know to operate a particular peripheral.) The symbols defined by some libraries/headers (e.g. in the hardware include directory) can also be convenient to avoid having so many magic numbers in the code. Of course the problem could be in code not shown (e.g. are you sure the ISR is being called at the appropriate times (how are startTick and endTick initialized, how are interrupt vectors set), how is a completed pulse detected, etc.) Quote Link to post Share on other sites
flek12345 0 Posted November 25, 2014 Author Share Posted November 25, 2014 Finally, I managed to get some results... There is a problem in counting direction. I thought that I set up timer to count down. TIMER0_TAMR_R = 0x00000002; // 3) configure for periodic mode, default down-count settings But timer is counting UP. I debug it, and I see that endTick is bigger than startTick. When I calculate in this way: deltaTick = endTick - startTick; I get correct result. But, I still do not understand why timer is counting up. I thought that bit 4 (TACDIR) is defining counting direction. And in my setup it is 0. And documentation said "0 The timer counts down". Concerning link: http://www.ti.com/tool/sw-tm4c It does not work. Quote Link to post Share on other sites
igor 163 Posted November 25, 2014 Share Posted November 25, 2014 The link works just fine if you take off the space that somehow got added to the end of it. http://www.ti.com/tool/sw-tm4c (Stupid BBS software - should do a better job of validating input and ignoring spurious characters. Are there any web sites/servers that allow a trailing space in the URL?) Or just use your favorite search engine to look for Stellarisware or Tivaware. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.