Signal Generator with Arduino Leonardo (ATmel32u4)

Hello People,

I am working on an Arduino Leonardo and I am trying to implement a signalgenerator.

First I want to do a simple rectangular signal.

My first try was to simply use digitalWrite() and set the Output to high, wait some time, set it to low and wait the same time through delay().

I noticed that the digitalWrite() function is quite slow and that delay() is not precise enough. So I am using now to set the Output and reset it a true c command and instead of delay() I am using delayMicroseconds().

It is not working so well thats why I am here.

while(1)
{
PORTC |= _BV(PC6);
delayMicroseconds(300);

PORTC &= ~_BV(PC6);
delayMicroseconds(300);
}

This simple programm should turn on the Output PC6 wait 300us turn it off and wait again, and repeat.
I connected this to an oscilloscope and I am posting the picture now.

As you can hopefully see in the attached picture, the high and low time should be exactly the same. but the high time is something around 400us and the low time around 200us.

I googled a lot and I have no freaking idea whats happening, maybe some of you guys had the same issue.

thanks a lot, cheers

Read the datasheet for the processor chip you have and use a Timer to generate the 50% duty cycle .
Change your post title to "How use TIMER for 50% duty cycle waveform at [frequency] hz."

krysis:
I noticed that the digitalWrite() function is quite slow and that delay() is not precise enough. So I am using now to set the Output and reset it a true c command and instead of delay() I am using delayMicroseconds().

Well, if the optimiser is working correctly, digitalWrite() will code exactly to the "true C command" you have written.

Presumably, both "read-modify-write" commands should be symmetric and take the same number of cycles to execute, but perhaps they are not being optimised in the same manner.

The problem with delayMicroseconds() is the same as with delay() - they specify a delay, but that corresponds only to their own execution, taking no account of the times all the other code requires. It would seem that the code implementing "while(1)" is not so straightforward and is evaluating something to make a decision - "while(TRUE)" might possibly work better. Rather than using delayMicroseconds(), you need to use your own code that checks the microseconds value against a number determined by adding the interval to its previous value.

krysis:
As you can hopefully see in the attached picture, the high and low time should be exactly the same. but the high time is something around 400us and the low time around 200us.

I cannot explain why any part would be less than 300 µs.

The attached program generates two 50% duty cycle waveforms, one on pin-9 (150khz) and another on pin-11 (175hz).(PB1 & PB3) During testing phase I connected a pot wiper to A0 and mapped the pot position to the range of adjustment I wanted in the timer count range so if the count 150 was midpoint I mapped it so I could reduce or increase the frequency of the 50% duty cycle waveform by whatever amount I wanted like +/- count of 50 making the timer count 100 to 200 . When I measured the frequency that gave me the result I needed for my application (HV Power supply) , I hard coded that count and got rid of the pot. You can look at the code and the datasheet for your processor and figure out what needs to be changed for your application. Guaranteed 50/50 duty cycle.

EL_Backlight_PS_H_150_kHz_L_175_Hz.ino (1.05 KB)