cancel
Showing results for 
Search instead for 
Did you mean: 

Bit banging timer problem

j239955_st
Associate II
Posted on July 24, 2015 at 10:18

Greetings,

this is my first post here, so I'll start with some background information. My name is Jan and I've been working with the STM32 F407 for a few month now. This forum really helped me a lot and so far I was able to solve any problems I had with your help, for which I'd like to thank you all! 🙂

I'm currently trying to add a bitbanging function for a rgb LED. I already wrote a 1wire connection, which was no problem, so I thought this is an easy thing, but I'm struggling with the required speed.

All I needed is a different timer config, because the given period length is 1.25us in which I need a high and low signal. Since the GPIOs need about 100ns to reach the steady state, I was aiming for a timer tick frequency of 10MHz, however I can't get above 2,5MHz.

For the prescaler calculation I use the formula

prescaler = (timer default frequency (168MHz) / (period * frequency)) - 1

The formula works for every lower frequency, so probably it's a hardware limitation I'm not aware of.

I would provide the code, but it's really just a simple timer, so it probably wouldn't help.

I'm aware that there are other solutions like PWM or inline assembler, but I still wonder why it doesn't work.

Thanks in advance, I appreciate every help that I can get!

Edit: To clarify, my prescaler for 2,5MHz is 33, which is correct, but if I go down to 0 the frequency doesn't get higher than 2,8MHz, so the 2,5MHz is the last value were my formula works.

I'm measuring the frequency with an GPIO Pin, which is toggled each time the timer update interrupt occurs, could that be a problem?
5 REPLIES 5
Posted on July 24, 2015 at 10:40

Well the real limitation is that you have integer dividers, and some times you have to change the clocking strategy to fit the numbers you want to hit. ie run the part at 150 MHz, and not at 168 MHz, or use magic crystals.

Frequency = TIMCLK / (P * Q);

Where Prescaler = P - 1; and Period = Q - 1; and P is 16-bit and usually the smallest value.

If TIMCLK = 150 MHz, P = 1, and Q = 15, you have a timer with a 10 MHz update (rollover) frequency.

800 KHz is divisible into 168 MHz, as is 2.4 MHz

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
j239955_st
Associate II
Posted on July 24, 2015 at 11:09

Thank you for your quick response!

The integer division is plausible, but if I choose my TIMCLK = 168MHz, P = 1 and Q = 10 my update frequency had to be 16,8 MHz, but what I get is 2,778MHz. My frequency doesn't really has to be accurate, since the signal length of high and low is quite tolerant. In case my config is wrong, I'll add the relevant code. The used timer is TIM10 on APB2.


void
delay_bitBanging_init()

{

NVIC_InitTypeDef NVIC_InitStruct;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;


switch
(delay_getAPB(DELAY_TIM_BB))

{

case
1:

RCC_APB1PeriphClockCmd(delay_getAPBclock(DELAY_TIM_BB), ENABLE);

break
;

case
2:

RCC_APB2PeriphClockCmd(delay_getAPBclock(DELAY_TIM_BB), ENABLE);

break
;

}


TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseStruct.TIM_Period = 9;

TIM_TimeBaseStruct.TIM_Prescaler = 0;

TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;

TIM_TimeBaseInit(DELAY_TIM_BB, &TIM_TimeBaseStruct);


NVIC_InitStruct.NVIC_IRQChannel = delay_getIRQChannel(DELAY_TIM_BB);

NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;

NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;

NVIC_Init(&NVIC_InitStruct);


TIM_ITConfig(DELAY_TIM_BB, TIM_IT_Update, ENABLE);

TIM_Cmd(DELAY_TIM_BB, ENABLE);

}


void
TIM1_UP_TIM10_IRQHandler()

{

if
(TIM_GetITStatus(DELAY_TIM_BB, TIM_IT_Update) == SET)

{

TIM_ClearFlag(DELAY_TIM_BB, TIM_FLAG_Update);

GPIO_ToggleBits(GPIOE, GPIO_Pin_2);

}

}

Danish1
Lead II
Posted on July 24, 2015 at 11:45

Is it possible that 2.8 MHz is simply as fast as the processor can execute all the instructions it needs to in order for respond to the interrupt?

The processor is running at 168 MHz, so 2.8 MHz is 60 processor cycles.

The processor takes 12 cycles to save its current state in response to an interrupt (plus a further 17 if it has to save floating-point registers as well) and you can reckon on a similar number to restore its state on return from interrupt.

So that means you only have 36 processor cycles to execute the interrupt code. Each C instruction translates to several processor cycles, and a function call has the call-overhead as well as however many instructions there are inside the function.

I guess you compiled the code with full optimisations turned on, but short of going to hand-crafted machine code I would not expect much scope for improvement.

Hope this helps,

Danish

j239955_st
Associate II
Posted on July 24, 2015 at 12:23

Thanks, that could definitely be a reason.

I already had it working, but I didn't use interrupts and worked directly with the count register. The thing I didn't like about it is, that the delay function wasn't linear, so when I called the function with delay(5) and then with delay(10) the pause wasn't twice as long as one would expect. So I had to approximate the right values, which did work, but I wouldn't call it a smooth code.

Like I said, there are still the options to do it with inline assembler or PWM, but I want to make sure it wasn't just a stupid mistake by me 🙂

Thanks again for the help!

Posted on July 24, 2015 at 14:52

Not sure assembler is going to help.

You can modulate PWM via DMA, or output a pattern buffer via timed DMA to GPIO pins.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..