This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335x measuring PWM pulse width in Timer capture mode

Other Parts Discussed in Thread: AM3358

I am searching for example C programming code to use the timers (DMTimer4-DMTimer7)on the Beaglebone Black Rev C using the Sitara AM3358 MCU processor. The objective is to read the pulse-width time from PWM signals. I want to use four 16-bit I/O timers simultaneously in input capture mode with some set to rising edge detection and others set to falling edge detection. The programmer's reference manual does not provide any sample code or examples. Can you provide me with source C code examples or direct me to a link?

In addition, I would like to invoke the FPU (Floating Point Unit) for complex mathematical operations. I was wondering if you have any source code examples to accomplish this task?

Any guidance/assitance or direction to resources would be helpful.

  • Hi Peter,

    Are you looking for Linux drivers or bare-metal code?

  • Hi Biser,

    I am looking for bare-metal C source code to run on the BeagleBone Black.

    Thanks, Peter
  • I'm sorry, we don't have any bare-metal example code for DMTimer capture mode.
  • Hi Biser,

    Can you provide me with a link or other means to access the Linux drivers - source "C" example code for the DMTimer input capture mode? 

    Thanks, Peter

  • Hi Peter,

    The linux kernel code can be found here:
    www.ti.com/.../PROCESSOR-SDK-AM335X

    The timer drivers are:
    arch/arm/mach-omap2/timer.c
    arch/arm/plat-omap/dmtimer.c

    Unfortunately those are only initialization sources. Any additional functionality should be implemented by the user.

    Best Regards,
    Yordan
  • Peter Jacquemin said:
    The objective is to read the pulse-width time from PWM signals.

    Haven't tested this, but should be pretty straightforward:

    • setup pinmux, enable timer
    • let the timer run freely (TLDR=0), fast as possible (24 MHz with prescaler disabled)
    • enable capture of two events (CAPT_MODE=1) on either edge (TCM=3) for measuring pulse width or single edge (TCM=1 or 2) for measuring pulse distance (hence frequency)
    • when the timer has captured two edges it signals the TCAR interrupt flag. You read the two timestamps from the TCAR and TCAR2 registers and subtract them to obtain. Clearing this flag will rearm the timer to capture again 

    Some other stuff that you may want to double-check is

    • clksel_timer[4-7]_clk in PRCM should be set to 1
    • timer interface should be in non-posted mode (TSICR == 0)
    • timer[5-7]_evtcapt (timer event mux) in Control Module should be set to 0

    Note that the eCAP modules are much fancier for capturing edges, with a buffer/fifo for up to four timestamps, thus allowing PWM frequency and duty cycle to be obtained at the same time. They also run at much higher frequency hence give better resolution. The beaglebone however has fewer eCAP modules than capture-capable timers.

    Peter Jacquemin said:
    I want to use four 16-bit I/O timers

    Both DMTimer and eCAP use 32-bit timers and timestamps.

  • Peter Jacquemin said:
    In addition, I would like to invoke the FPU (Floating Point Unit) for complex mathematical operations. I was wondering if you have any source code examples to accomplish this task?

    Complex floating-point numbers are natively supported by C since C99 (and before that by gcc as extension), e.g.:

    #include <complex.h>
    #include <math.h>
    #include <stdio.h>
    
    int main()
    {
            complex float z = (-1 + sqrtf(3) * I)/2;
            printf( "z = %g %+g i\n", crealf(z), cimagf(z) );
            z = csqrtf(z);
            printf( "√z = %g %+g i\n", crealf(z), cimagf(z) );
            return 0;
    }

    They're also supported by type-generic math (tgmath.h), and as extension gcc supports complex literals.

    C++ tried to make something similar with std::complex but it is far more painful to use:

    std::complex<float> z = 1;
    z = z + 1;      // error, no operator+ (std::complex<float>, int)
    z = z + 1.0;    // error, no operator+ (std::complex<float>, double)
    z = z + 1.0f;   // ok

     

    To use neon/VFP in a baremetal environment it first needs to be enabled in the cpu, typically during very early initialization in assembly since it must be enabled before executing any code produced by a C compiler which assumes there's neon/vfp support, since it may emit neon instructions even in code without any use of floating-point or vector types.

    Note that while Neon is fast on the cortex-A8, its floating-point behaviour isn't 100% IEEE-compliant (with regard to denormals and NaNs) and it has no support for double-precision floats at all. Therefore it embeds a VFP unit which performs IEEE-compliant single- and double-precision floating point, but it's very very slow.

    For a performance point of view it is therefore recommended to use floats instead of doubles when acceptable, and use -ffast-math to allow the compiler to disregard strict IEEE-compliance and therefore use Neon. To help avoid using doubles unintentionally, -fsingle-precision-constant may be convenient albeit invasive. There's also -Wdouble-promotion which tends to get spammy however and sometimes has false positives (e.g. when using tgmath).