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.

AM263P4: External Timer Trigger Functionality (pulse counter)

Part Number: AM263P4
Other Parts Discussed in Thread: LP-AM263P, TCA6416

Tool/software:

Hello,

I have an application in which I need to count pulses very rapidly (200kHz or so). So using the CPU and just reading the digital value of a pin every loop cycle is going to be limiting with the overhead of the rest of the code. My idea was to use an external clock trigger so that I could have a timer trigger an overflow interrupt every time it counts say 1000 pulses, that way it allows the CPU to do its thing while the timer handles counting pulses. Is this something that is possible with the AM263P4? If this specific idea isn't possible, is there any functionality that could mimic this? Thank you in advance for your help!

  • You can also set up a GPIO with an edge triggered interrupt and increment a counter every time the interrupt fires.

  • Hi Donnavan,

    You can use the PEU ICSS IEP Capture mode for this.

    So basically every pulse event gets captured in IEP capture registers. this is something we do for SENT protocol implementation.

    software-dl.ti.com/mcu-plus-sdk/esd/AM263X/latest/exports/docs/api_guide_am263x/SENT_DESIGN.html#autotoc_md1425

  • For code reference you can use the PRU code present here: github.com/.../main.asm

  • Hello, thank you for your response. That was my initial solution but it took too much CPU time once the interrupt was called to increment the counter and then return to where it was. Managed much faster speeds with that solution than my first attempt though which was just reading the pin every loop and having software edge detection. Not my finest code!

  • Thanks! I'm currently using the TI-LaunchPad for the AM263P4. Are there any GPIOs that don't require using the onboard MUXs? I'm not sure how to use those and it looks like all of the GPIOs that I could use for the PRU ICSS IEP go through MUXs.

  • Hello Donovan,

    The muxes are straightforward to use and we have examples that provide the code to use them. Which MUX would you like to use for this? I can go find an example with the code needed to provide you.

    Best Regards,

    Ralph Jacobi

  • Ah, I was under the impression they would require us to write a library for them but I guess I was mistaken. I can use any mux as long as it can be used for PRU ICSS IEP via a GPIO pin. Thank you for the help!

  • Hi Donovan,

    Got it, I'm going to have our PRU ICSS HW expert take a look through the LP-AM263P routing options and recommend a pin for you then.

    Best Regards,

    Ralph Jacobi

  • Donovan, 

    Any of the PR0_PRU0_GPIOx pins routed out to the boosterpack headers on the LP-AM263P are acceptable for this application. The PR0_PRU0_GPIOx signals are routed through on-board MUXes, so it is important to first configure the MUX for the appropriate routing. 

    Please let me know if you have any additional questions on configuring the on-board muxes to route out the PR0_PRU0_GPIOx pins. You can refer to the schematics here:

    https://www.ti.com/lit/zip/sprr503

    Regards,

    Brennan

  • Hello Brennan, thanks for your input, I'll try to get the MUX working, thanks for your help!

  • Hello, this is exactly what I was looking for! Thanks!

  • Donovan,

    The source code and API header file for the I2C controlled IO expander (needed to control the MUX select line) can be found at C:\ti\mcu_plus_sdk_am263px_10_00_00_35\source\board\ioexp. Ensure you are looking at the TCA6416 files - this is the part number of the IO expander on the LP-AM263P.

    Regards,

    Brennan

  • I'm trying to use the PRU ICSS IEP to act as a pulse counter that triggers an interrupt upon reaching a certain value (for example, every 16 pulses it triggers and interrupt). I'm very confused as to exactly what IEP does for this, and I'm struggling to see how the example code does this. From what I read about the PRU ICSS, I gather that I'm supposed to use the capture and compare registers in the PRU (I think) to do the pulse counting and interrupt triggering, but the primary things that I'm getting stumped on are:

    • How do I set the clock input to a physical pin on the GPIO?
    • How do I enable an interrupt that triggers when the clock reaches a certain value?
    • Once I enable the interrupt, what is the callback for it?

    Thank you guys for your help, I really appreciate it!

  • Hi, 

    Sorry for delayed response, we missed this e2e thread as you marked this as resolved, from next time please create new e2e thread if you have any follow up questions to avoid confusion.

    you can find below PRU code, which has 2 approaches to trigger interrupt to R5F from PRU on reaching pulse count along with answers to your questions in comments

    Let us know if you need any help.

    ; Copyright (C) 2025 Texas Instruments Incorporated - http://www.ti.com/
    ;
    ; Redistribution and use in source and binary forms, with or without
    ; modification, are permitted provided that the following conditions
    ; are met:
    ;
    ; Redistributions of source code must retain the above copyright
    ; notice, this list of conditions and the following disclaimer.
    ;
    ; Redistributions in binary form must reproduce the above copyright
    ; notice, this list of conditions and the following disclaimer in the
    ; documentation and/or other materials provided with the
    ; distribution.
    ;
    ; Neither the name of Texas Instruments Incorporated nor the names of
    ; its contributors may be used to endorse or promote products derived
    ; from this software without specific prior written permission.
    ;
    ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    ; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    ; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    ; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    ; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    ; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    ; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    ; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    
    ;************************************************************************************
    ;   File:     main.asm
    ;
    ;   Brief:    Template asm file example
    ;************************************************************************************
    
    ; CCS/makefile specific settings
        .retain     ; Required for building .out with assembly file
        .retainrefs ; Required for building .out with assembly file
    
        .global     main
        .sect       ".text"
    
    ;************************************* includes *************************************
        .include    "icss_pin_macros.inc"
        .include    "icss_iep_regs.inc"
        .include    "icss_iep_macros.inc"
    
        .asg	R2,	   CUR_PULSE_COUNT
        .asg    R3,    TOT_PULSE_COUNT
        .asg    R4,    TEMP_REG1
    
    FILTER_CYCLES       .set       3
    PRU_PIN             .set       0
    
    
    m_wait_for_cap6_rise    .macro
        ;wait until cap6 rise event
    wait?:
        lbco        &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CAP_STATUS_REG, 4
        qbbc         wait?, TEMP_REG1, 6    
        ;read cap6 value to clear capture status
        lbco        &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CAPR6_REG, 4
        .endm
    
    ;********
    ;* MAIN *
    ;********
    
    main:
    
    init:
    ;----------------------------------------------------------------------------
    ;   Clear the register space
    ;   Before begining with the application, make sure all the registers are set
    ;   to 0. PRU has 32 - 4 byte registers: R0 to R31, with R30 and R31 being special
    ;   registers for output and input respectively.
    ;----------------------------------------------------------------------------
    ; Give the starting address and number of bytes to clear.
        zero	&r0, 120
        ldi     TOT_PULSE_COUNT, 1000
        ldi     CUR_PULSE_COUNT, 0
    
        ;************************************************************
        ;               Polling PRU GPI(Approach 1)
        ;
        ;************************************************************
    
    wait_for_next_pulse:
        m_wait_low_pulse    FILTER_CYCLES, PRU_PIN
        ADD     CUR_PULSE_COUNT, CUR_PULSE_COUNT, 1
        qbne    wait_for_next_pulse, CUR_PULSE_COUNT, TOT_PULSE_COUNT
        LDI     CUR_PULSE_COUNT, 0
        ;Generate interrupt to R5F(refer 7.2.5.2.2.2 of Technical reference manual for more details)
        ;pr0_pru_mst_intr[0]_intr_req ---> Host Interrupt 2 (INTC Mapping can be done from PRUICSS sysconfig module)
        ;Host Interrupt 2 ---> R5FSS0_CORE0_INTR_PRU_ICSSM0_PR1_HOST_INTR_PEND_0 (This mapping is fixed)
        ;R5FSS0_CORE0_INTR_PRU_ICSSM0_PR1_HOST_INTR_PEND_0 can be mapped to ISR(refer <sdk_path>/examples/gpio_input_interrupt)
        LDI     R30.b0, 0x20
        qba     wait_for_next_pulse     
    
        ;************************************************************************************************************************************
        ;               Using IEP capture mode (Approach 2)
        ;   Use IEP_CAPR6_REG0/IEP_CAPR6_REG1 which can capture time stamp of IEP on rise Edge of PRGn_IEP0_EDC_LATCH_IN0(SOC level IO signal)
        ;************************************************************************************************************************************
    
    iep:
    	; disable iep timer
        m_set_iep_global_cfg_reg   	0, TEMP_REG1, 0x20
        ; set starting count value of IEP counter
        m_set_iep_count_reg0       	0, TEMP_REG1, 0xffffffff
        m_set_iep_count_reg1       	0, TEMP_REG1, 0xffffffff
    	;Enable the reset of iep counter with compare 0
    	ldi     TEMP_REG1,  0x03
    	sbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CMP_CFG_REG, 4
    	fill	&TEMP_REG1, 0x4
    	sbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CMP0_REG, 4
    	;clear the compare status
    	ldi     TEMP_REG1, 0x01
    	sbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CMP_STATUS_REG, 4
    	;set cap 0 to 7 in continouous mode with External capture enable
    	ldi     TEMP_REG1,  0x00
    	sbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CAP_CFG_REG, 4
    	lbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CAPR0_REG, 4
        lbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CAPR1_REG, 4
        lbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CAPR2_REG, 4
        lbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CAPR3_REG, 4
        lbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CAPR4_REG, 4
        lbco    &TEMP_REG1, ICSS_IEP_CONST, ICSS_IEP_CAPR5_REG, 4
    	; Start IEP timer with increment of 5 (increment of 1->1ns)
        m_set_iep_global_cfg_reg   0, TEMP_REG1, 0x51
    
    wait_for_next_capture_event:
        m_wait_for_cap6_rise
        ADD     CUR_PULSE_COUNT, CUR_PULSE_COUNT, 1
        qbne    wait_for_next_capture_event, CUR_PULSE_COUNT, TOT_PULSE_COUNT
        LDI     CUR_PULSE_COUNT, 0
        ;Generate interrupt to R5F(refer 7.2.5.2.2.2 of Technical reference manual for more details)
        ;pr0_pru_mst_intr[0]_intr_req ---> Host Interrupt 2 (INTC Mapping can be done from PRUICSS sysconfig module)
        ;Host Interrupt 2 ---> R5FSS0_CORE0_INTR_PRU_ICSSM0_PR1_HOST_INTR_PEND_0 (This mapping is fixed)
        ;R5FSS0_CORE0_INTR_PRU_ICSSM0_PR1_HOST_INTR_PEND_0 can be mapped to ISR(refer <sdk_path>/examples/gpio_input_interrupt)
        LDI     R30.b0, 0x20
        qba     wait_for_next_capture_event