Hi there, my project requires me to generate a 1.2 MHz signal. Is there a way to make a digital pin write out at that speed?
Yes. Search for "Direct Port Manipulation".
I'm using the code in the arduino page, as well as some code that someone else posted online, and I'm not getting any signal being outputted.
Just to test, my code is:
int ledPin = 4; // LED connected to digital pin 13
void setup()
{
pinMode(ledPin, OUTPUT); // sets the digital pin as output
}
void loop()
{
PORTD = B00010000;
PORTD = B00000000;
}
I'm using a Mega2560, could that be why it's not working? Or am I doing something completely wrong?
How do you know it's not working, you can't see that frequency.
Also it may not be possible to get exactly 1.2Mhz and using a loop the waveform won't be a 50% duty cycle. Does any of that matter to your application?
EDIT: On the 2560 pin 4 is PORTG bit 5. You are using PORTD bit 4 which is not connected to anything on the Mega.
Try PORTB bit 7 for the LED, but as I said at that speed you need instruments to see it.
Try
void setup()
{
pinMode(13, OUTPUT); // sets the digital pin as output
}
void loop()
{
PORTB = B10000000;
PORTB = B00000000;
delay (1000);
}
To verify that the LED is blinking.
Rob
Awesome, thank you for all the help. Duty cycle is not an issue, but I do need to be close to 1.2 MHz. I will fiddle with it. Is there any way I can induce a delay that's less than a microsecond to control the frequency?
I was using an oscilloscope to see the signal.
Is there any way I can induce a delay that's less than a microsecond to control the frequency?
At that frequency the only real option is to insert dummy instructions, for example
asm ("nop");
will insert a 62.5nS delay. So write the tightest loop you can (as above) then if it's too fast start adding NOPs. If it's too slow get an ARM
Bottom line is that your basic resolution is 62.5nS so you should be able to tune it to within that res.
Rob
I think you need
DDRB = B1111111; // for all 8 bits to be outputs on Port B
following this info:
/* Each port is controlled by three registers, which are also defined variables in the arduino language.
The DDR register, determines whether the pin is an INPUT or OUTPUT. (DDRx)
The PORT register controls whether the pin is HIGH or LOW. (PORTx)
The PIN register reads the state of INPUT pins set to input with pinMode(). (PINx)
DDR and PORT registers may be both written to, and read.
PIN registers correspond to the state of inputs and may only be read.
Example
DDRD = B11111110; // sets Arduino pins 1 to 7 as outputs, pin 0 as input
DDRD = DDRD | B11111100; // this is safer as it sets pins 2 to 7 as outputs
// without changing the value of pins 0 & 1, which are RX & TX
PORTD = B10101000; // sets digital pins 7,5,3 HIGH
*/[code]
[/code]
Graynomad:
How do you know it's not working, you can't see that frequency.Also it may not be possible to get exactly 1.2Mhz and using a loop the waveform won't be a 50% duty cycle. Does any of that matter to your application?
EDIT: On the 2560 pin 4 is PORTG bit 5. You are using PORTD bit 4 which is not connected to anything on the Mega.
Try PORTB bit 7 for the LED, but as I said at that speed you need instruments to see it.
Try
void setup()
{
pinMode(13, OUTPUT); // sets the digital pin as output
}
void loop()
{
PORTB = B10000000;
PORTB = B00000000;
delay (1000);
}
To verify that the LED is blinking. ______ Rob
Awesome, that totally works! Using your sample code, and getting rid of that delay(1000), I was able to get a 934kHz signal, which is usable.
My only question now is that this is done by NOT using ANY other commands. I'm using my microcontroller to read in a signal and perform some calculations on it and output it to a serial, as well as creating this signal. Once I introduce those other commands, it's going to slow this signal down right? Is there any way around that, or is my knowledge of arduino code just too basic?
it's going to slow this signal down right?
Yep.
Is there any way around that
Not if you need the signal to be constant.
If you are happy to read and calculate outside this loop then you can do that, but if this extra work has to be done constantly you are in trouble.
In this case you are better using one of the hardware timers, they can be "set and forget" with no further software intervention and they are not affected by any code running.
Rob
Is there any way around that, or is my knowledge of arduino code just too basic?
The way around is to program one of the timers to drive PWM pin.
http://arduino.cc/playground/Code/PwmFrequency
This can be done by using the 'Toggle OC2A on Compare Match' mode along with the 'Clear Timer on Compare Match (CTC)' mode of Timer/Counter2. This sounds complicacted, but as I recall it only takes about four instructions, all in setup().
The disadvantage of this technique is that the output pin is fixed by the hardware. It also ties up a timer (timer 2 in this case).
The advantage is that this technique does not use any interrupts and does not use any processor time once it is set up.
I have some (untested) code around here somewhere, I'll try to dig it up tomorrow and test it out.
Don
Thank you, I appreciate it.
I'll also try modifying the PWM timer.
I have some (untested) code around here somewhere, I'll try to dig it up tomorrow and test it out.
Here it is - it worked for me!
// Arduino - v1.0
// Arduino Duemilanove
#define outpin 11 // OC2A pin - cannot be changed
#define clockFrequency 16000000 // Arduino clock frequency
#define outputFrequency 1000000 // desired output frequency
#define prescaleFactor 1 // the only choice to get 1 MHz out
void setup ()
{
TCCR2B = B00000001; // set CS20, clear CS21, CS22 and WGM22
TCCR2A = B01000010; // set COM2A0 and WGM21, clear COM2A1 and WGM20
OCR2A = ((float)clockFrequency / (outputFrequency * 2 * prescaleFactor)) -1; // timer data
pinMode(outpin, OUTPUT); // turn on output pin
// the timer runs with no additional code and no use of interrupts
// do whatever else you want to do here
}
void loop ()
{
// do whatever else you want to do here
}
Don
That's perfect, exactly what I need, thank you!
Just to confirm, is that pin the same pin on the Mega2560? Or is there a place I can check which pin is what online?
Just to confirm, is that pin the same pin on the Mega2560? Or is there a place I can check which pin is what online?
I wouldn't count on it. As far as I can tell from the hodgepodge that they call a 'Schematic' diagram it is Pin 10.
By the way you should be able to turn the square wave off with
TCCR2B = B00000000;
and back on again with another
TCCR2B = B00000001;
.
Don
Edit: It looks like it is indeed digital pin 10 according to: http://arduino.cc/en/Hacking/PinMapping2560
So your code works amazingly, I'm just having an issue, at frequencies above 1.5Mhz, I can't really get it to work. I either lock it to 1.6Mhz, 2Mhz or 2.6Mhz. I need it at either 1.8 or 2.3 Mhz but I can't get it to those values. Does anyone have any suggestions?
Does anyone have any suggestions?
Not if you are going to use the 'Toggle OC2A on Compare Match' & 'Clear Timer on Compare Match (CTC)' technique. If you rework the equation used to calculate the 'timer data' you find that the output frequency is determined by dividing the clock frequency by 2 * prescaleFactor * (1+timerData). This is the equation in section 17.7.2 of the datasheet. Since the timerData is an integer there are a limited number frequencies that you can get and they are widely spaced at the upper frequency end.
You can probably use the timer/counter to get a lot closer to the frequency you desire, but not without using some combination of processor time and interrupts.
Don
You can probably use the timer/counter to get a lot closer to the frequency you desire
Changing the crystal can help, at the possible expense of stuffing up other thing like serial and of course actual programming the chip
As Don said you are working with integer division and at the high freqs there aren't many options.
It may be better to go back to the software loop with NOP padding idea but I guess that was a problem because you want to run other code at the same time.
Maybe an external clock generator of some kind is needed.
Rob