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.

Compiler/CC2541: CC2541

Part Number: CC2541

Tool/software: TI C/C++ Compiler

Good Day To All,

Just need your input/s regarding my issue here.

I initialize Timer 1 channel 3 (P0_7) in input capture mode like below:

PERCFG |= BV(6); //timer 1 alternative 2 config

P2DIR = (P2DIR & ~0xC0) | 0x80); // give priority to timer 1

P0SEL |= BV(7);//set port 0 pin 7 as peripheral

P0DIR |= BV(6);//set P0_6 as output and synch with P0_7 input interrupt...

T1CCTL3 |= BV(6); //enable interrupt at timer 1 channel 3

T1CCTL3 |= BV(1) | BV(0); //capture on all edges..

P0IEN |= BV(7); //enable interrupt at P0_7.. i am not sure if this is redundant declaration..

T1IE = 1; //enable interrupt at timer 1

Then at "hal_key.c", I editted the ISR function for PORT 0 as below:

HAL_ISR_FUNCTION(halKeyPort0Isr, T1_VECTOR)

{

HAL_ENTER_ISR();

if (P0IFG |= BV(7))

{

if(P0_6  == 1){P0_6  = 0;}else{P0_6  = 1;} //test code...toggle pin output, should synch with P0_7 external signal...

}

P0IFG = 0; //reset flag

HAL_KEY_CPU_PORT_0_IF = 0; //reset P0IF

CLEAR_SLEEP_MODE();

HAL_EXIT_ISR();

return;

}

I use oscilloscope to check the PWM produced in the external input for P0_7 then compare with P0_6 output pulses.

I assumed that the P0_6 should be in synch with P0_7 but there are unwanted steady HIGH/LOW signals in between.

This can't be good for my application since i am going to get the period and duty cycle (at T1CC3L:T1CC3H) of the external input by the use of interrupt.....or no need? just read the registers directly in a periodic approach?

Kindly provide some insights with my situation here.

I used "simpleBLEperipheral" sample as base project.

Thanks.

  • Additional info.
    when i change the conditions inside the ISR function from if (P0IFG |= BV(7)) to if (P0IFG && BV(7)), I manage to filter out the Long High Signal in the output. now the problem is the Long Low Signal still apparent. Instead of a regular 1010101010 pulses, i get 1010100000010101010100000101010000... so on.. you get the idea :)
  • Hello Robert,

    In the CC2541 users guide section 9.10 Timer 1 Interrupts it is stated: "The CPU interrupt flag IRCON.T1IF is also set when a Timer 1 source interrupt flag is being cleared and one or more other Timer 1 source interrupt flags are still set while the corresponding interrupt mask bit is set."

    Try to change from:

    HAL_KEY_CPU_PORT_0_IF = 0; //reset P0IF

    to:

    T1IF = 0;

    Also use a separate suitable name for your T1 interrupt routine such as for example timer1_ISR instead of halKeyPort0Isr. Probably does not change anything functionally, but it makes it more readable.

  • Hello Sir Eirik,

    Thanks for the reply.
    I already applied what you suggest but still same behavior, there is still long low signal displayed in oscilloscope. I even set both T1IF and P0IF to 0 but still the same..

    Yes i will edit my code just like you suggested to be readble.
    Thanks.
  • Hey Robert,

    Check out the t1_cap example code in CC2541/43/44/45 Peripherals Software Examples. Make an entirely new ISR and leave the button ISR alone. Also disable the pin interrupt on P0.7.

    Here is a rough untested idea:

    #define T1STAT_CH3IF 0x08
    
    HAL_ISR_FUNCTION(timer1_ISR, T1_VECTOR) {
        HAL_ENTER_ISR();
        if (T1STAT && T1STAT_CH3IF )) {
           P0_6  ^= 1; // Toggle P0.6
        }
        // Clear Timer 1 channel 3 interrupt flag. The proper way to clear interrupt
        // flags is by just writing 0, for R/W0 operations search datasheet.
        T1STAT = ~T1STAT_CH3IF;
        CLEAR_SLEEP_MODE();
        HAL_EXIT_ISR();
        return;
    }

  • Hello Sir Eirik,

    I just tried your suggestions and unfortunately, the signal output returns to irregular long High/Low mixed with expected high/low signals.

    I will try to check the t1_cap example now.

    Thanks.

  • Hello Again,

    This is the first time I see and tested the t1_cap example you recommended.
    Tried to replace pin assignments to my needs and I notice a behavior with the output signal. When I compare the external signal with the toggling pin output, it seems that the input signal's period and duty cycle was x2 at output toggled pin at every interrupt. And also, when the duty cycle of the input signal increases, there was no changes in duty cycle of the output signal.
    Why is this happening?
    Edited process inside the interrupt with only T1STAT = ~T1STAT_CH0IF; and P0_6 ^= 1; but still the same behavior......
    Is this normal?
    Thanks.
  • Hello Robert,

    What is the frequency of your input signal?

    The channel input pin is synchronized to the internal system clock. Thus, pulses on the input pin must have a minimum duration greater than the system clock period. Please refer to section "Power Management and Clocks" in the CC2541 user guide to understand what the system clock speed is.

    Can you show me a combined plot of both the input signal and output signal?

    In the t1_cap example:

    • the input is only captured on falling edge end hence it is expected that the output P0.6 will have half the duty cycle of the input signal.
    • The prescaler is set to divider value to 32 to get a tickspeed of 500 kHz.

  • Hello Sir Eirik,

    Around 1250Hz. It is very much periodic.
    Yes i also considered those factors (prescaler, etc.) and change the interrupt to both Rising and falling edge to mimic the input signal.
    As of now, i cannot provide a graphical representation of my readings but i will try, to follow....
    Thanks.
  • Hello Again,

    Just this moment, i tried to recompile the t1_cap. before the PWM signals are not the same. i think i might have missed the edge interrupt settings to "both". Now it is working well, with respect to the t1_cap sample but not yet with my project :)
  • Great, then it should be possible to fix in your application.
  • Good Day Again Sir Eirik,

    I just tried applying the code of t1_cap with my application but unfortunately, it still not working well. There are still stray signals (long high/low) unlike with the sample's clean signals synch with the input.

    I think the BLE functions affect this timer 1 operation but i can't trace it yet. Kindly provide more hints.

    Thanks.

  • Hello Sir Eirik,

    As I dig deeper to the functions that may affected the timer 1 interrupt, I managed to make a work around the code by commenting out the Hal_ProcessPoll() function at OSAL.c and initializing LL_EXT_HaltDuringRf(LL_EXT_HALT_DURING_RF_DISABLE)..
    Now the output signal is in-synch with the external input signal. But still need to confirm what already working function/s will be affected to my program.
    For now, my problem is measuring the PWM (duty cycle and period).
    I know the code i use below is not efficient since i read some erratic values:

    HAL_ISR_FUNCTION(timer1_ISR, T1_VECTOR)
    {
    T1STAT = 0;
    P0_6 ^= 1;
    if (P0_6 == 1)
    {
    TempPeriod = (uint16) T1CC3L;
    TempPeriod |= (uint16) (T1CC3H << 8);
    TempPeriod += TempDutyCycle;
    }
    else
    {
    TempDutyCycle = (uint16) T1CC3L;
    TempDutyCycle |= (uint16) (T1CC3H << 8);
    }
    return;
    }

    I tried every prescaler available (1,8,32, 128) but still erratic readings.
    My external signal is around 820microseconds period and around 50% duty cycle so around 1210-1230 Hz.
    Kindly give hints on how to approach this problem.
    Thanks.
  • Hello Again Sir Eirik,

    I manage to made progress with my application and i just want to confirm with you if this is correct.

    HAL_ISR_FUNCTION(timer1_ISR, T1_VECTOR)
    {
    T1STAT = 0;
    P0_6 ^= 1;
    if (P0_6 == 1)
    {
    TempPeriod = (uint16) T1CNTL;
    TempPeriod |= (uint16) (T1CNTH << 8);
    T1CNTL = 0;
    T1CNTH = 0;
    }
    else
    {
    TempDutyCycle = (uint16) T1CNTL;
    TempDutyCycle |= (uint16) (T1CNTH << 8);
    T1CNTL = 0;
    T1CNTH = 0;
    }
    return;
    }

    Thanks.
  • Hello Robert,
    By commenting out the Hal_ProcessPoll() you will disable power saving (ALLOW_SLEEP_MODE(); is called in Hal_ProcessPoll to allow sleep). When entering sleep the device will usually enter PM2 if there is enough time and the power up delay and clock change during these transitions might be the cause for your observations.

    Also you can try to set HCI_EXT_ClkDivOnHaltCmd( HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT ); instead of LL_EXT_HALT_DURING_RF_DISABLE to avoid clock change during radio operations. However this will still delay processing as the CPU is halted.
    e2e.ti.com/.../255216
  • Hi Sir Eirik,

    Thanks for the confirmation and reference.
    I think i need to find a work around for the power saving issue because i still need that in my project. But since only the the allow sleep mode function is the issue, can I just call it when i am not using the timer 1 anymore? I think that is the most appropriate approach.

    Yes, the HCI_EXT_ClkDivOnHaltCmd( HCI_EXT_ENABLE_CLK_DIVIDE_ON_HALT ); is already initialize within my program.

    Thanks.
  • Hello Robert,
    I guess that will work.
    I meant to say disable:
    HCI_EXT_ClkDivOnHaltCmd( HCI_EXT_DISABLE_CLK_DIVIDE_ON_HALT );
  • Hi Sir Eirik,

    I thought i was wrong when i declared it as "Disable". Thanks for the confirmation.

    Regarding my Duty cycle and period reading, i read at T1CNTL and T1CNTH. My latest code inside the timer 1 ISR below:

    T1STAT = 0;
    if (P0_7 == 1)
    {
    P0_6 = 1;
    TempPeriod = (uint16) T1CNTL;
    TempPeriod = (uint16) (T1CNTH << 8);
    T1CNTL = 0;
    T1CNTH = 0;
    }
    else
    {
    P0_6 = 0;
    TempDutyCycle = (uint16) T1CNTL;
    TempDutyCycle = (uint16) (T1CNTH << 8);
    T1CNTL = 0;
    T1CNTH = 0;
    }
    return;


    But the ratio between the duty cycle and period in the registers are very off with the expected value which is around 45% - 50% duty cycle (now i get lower than expected). What could i have missed?
    Thanks.
  • Could it be?

    TempPeriod = (uint16) T1CNTL;

    TempPeriod |= (uint16) (T1CNTH << 8);

    TempDutyCycle = (uint16) T1CNTL;

    TempDutyCycle |= (uint16) (T1CNTH << 8);

  • Hello Sir Eirik,

    Sorry i missed that, i just typed it. My latest code is below for the Timer 1 ISR:

    T1STAT = 0;
    if (P0_7 == 1)
    {
    TempPeriod = (uint16) T1CNTL;
    TempPeriod |= (uint16) (T1CNTH << 8);
    T1CNTL = 0;
    T1CNTH = 0;
    P0_6 = 1;
    }
    else
    {
    TempDutyCycle = (uint16) T1CNTL;
    TempDutyCycle |= (uint16) (T1CNTH << 8);
    P0_6 = 0;
    }
    return;

    The value of TempPeriod is ok, but the DutyCycle is way below the expected value. I'm confused why this is hapenning, i did reset the register after acquiring the period so the 16-bit timer should start at 0x0000 then get Duty Cycle when falling edge is detected.

    Thanks.

  • Hello Again Sir Eirik,

    Already figured it out, my Period/DutyCycle acquisition actually has no problem. It was my notification to my client device that was off. The last decimal digit of my Duty cycle is not displayed.
    Now I can move on to I2C and beyond. :D
    Appreciate your time and guidance Sir.
    Thank you very much.