Offline
Newbie
Karma: 0
Posts: 23
|
 |
« on: March 08, 2012, 03:46:23 pm » |
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?
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Boston area, metrowest
Online
Brattain Member
Karma: 249
Posts: 16565
Available for Design & Build services
|
 |
« Reply #1 on: March 08, 2012, 03:48:44 pm » |
Yes. Search for "Direct Port Manipulation".
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 23
|
 |
« Reply #2 on: March 08, 2012, 04:28:43 pm » |
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?
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Online
Tesla Member
Karma: 73
Posts: 6838
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #3 on: March 08, 2012, 06:54:38 pm » |
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
|
|
|
|
« Last Edit: March 08, 2012, 07:00:36 pm by Graynomad »
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 23
|
 |
« Reply #4 on: March 08, 2012, 07:09:57 pm » |
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.
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Online
Tesla Member
Karma: 73
Posts: 6838
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #5 on: March 08, 2012, 07:18:43 pm » |
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
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
Boston area, metrowest
Online
Brattain Member
Karma: 249
Posts: 16565
Available for Design & Build services
|
 |
« Reply #6 on: March 08, 2012, 10:05:54 pm » |
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]
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 23
|
 |
« Reply #7 on: March 12, 2012, 12:53:27 pm » |
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?
|
|
|
|
|
Logged
|
|
|
|
|
nr Bundaberg, Australia
Online
Tesla Member
Karma: 73
Posts: 6838
Scattered showers my arse -- Noah, 2348BC.
|
 |
« Reply #8 on: March 12, 2012, 06:53:03 pm » |
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
|
|
|
|
|
Logged
|
|
|
|
|
Montreal
Offline
Edison Member
Karma: 17
Posts: 2207
Per aspera ad astra.
|
 |
« Reply #9 on: March 12, 2012, 07:40:34 pm » |
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
|
|
|
|
|
Logged
|
|
|
|
|
Western New York, USA
Offline
Faraday Member
Karma: 17
Posts: 3462
|
 |
« Reply #10 on: March 12, 2012, 09:59:59 pm » |
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
|
|
|
|
« Last Edit: March 12, 2012, 10:06:14 pm by floresta »
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 23
|
 |
« Reply #11 on: March 12, 2012, 10:43:24 pm » |
Thank you, I appreciate it.
I'll also try modifying the PWM timer.
|
|
|
|
|
Logged
|
|
|
|
|
Western New York, USA
Offline
Faraday Member
Karma: 17
Posts: 3462
|
 |
« Reply #12 on: March 13, 2012, 09:05:50 am » |
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
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Newbie
Karma: 0
Posts: 23
|
 |
« Reply #13 on: March 13, 2012, 02:08:54 pm » |
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?
|
|
|
|
|
Logged
|
|
|
|
|
Western New York, USA
Offline
Faraday Member
Karma: 17
Posts: 3462
|
 |
« Reply #14 on: March 13, 2012, 04:09:44 pm » |
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
|
|
|
|
« Last Edit: March 13, 2012, 04:26:32 pm by floresta »
|
Logged
|
|
|
|
|
|