Pages: [1]   Go Down
Author Topic: Use of direct port register to set PIN state without digitalWrite - Help needed  (Read 2258 times)
0 Members and 1 Guest are viewing this topic.
Milan
Offline Offline
Edison Member
*
Karma: 2
Posts: 1128
gioblu.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

HI guys, marry Christmas!
I am going crazy on a quite simple topic. I am trying to write faster functions to write / read digital ports with register.. instead of digitalWrite / Read

If I understand the way, this two lines do:
Code:
Code:
DDRC = B00000001;  // set analog 0 to OUTPUT
PORTC = B00000001; //set analog0 to HIGH

In BITreading i would have 1 or 0 in relation to pin state (I am building a custom protocol)
Code:
Code:
DDRC = B00000000; // set analog 0 input
PORTC = B00000000; // stop pull up
int BITreading = PINC & (1<<PC0); // get read value

In theory seems correct but don't works.
I try to print with serial BITreading, when I plug a 5v wire in the port, this is 1, but it takes many seconds to return to 0 after I remove the wire...quite strange.
Logged

Community robotica / programmazione Arduino
www.gioblu.com

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 525
Posts: 26523
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

When you remove the wire, there is nothing controlling the input, so the voltage "floats". 

That is why it is recommended to use the internal pullup resistor, and have an external switch, like your wire, connect to ground, and read 0 as the active state.

Or, use an external pulldown resistor and connect the pin high like you did.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Milan
Offline Offline
Edison Member
*
Karma: 2
Posts: 1128
gioblu.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, thanks for the reply. I am working on a single wire bidirectional custom protocol.
Now i can read using register, with this line:
Code:
int BITreading = PINC & (1<<B00000000);

But I get bugs, using the TX with register, this is the standard function that works with digitalWrite:
Code:
void writeBIT(int VALUE, int duration) {
    pinmode(inputPIN, OUTPUT);
    digitalWrite(inputPIN, VALUE);
    delayMicroseconds(duration - digitalRWTime); //for BITwidth
  }

I try like this:
Code:
void writeBIT(int VALUE, int duration) {
    DDRC = B00000001;
    if(VALUE == 1) { PORTC = B00000001; } else { PORTC = B00000000; }
    delayMicroseconds(duration - digitalRWTime);
  }

only crappy characters for now... where is the mistake?
Logged

Community robotica / programmazione Arduino
www.gioblu.com

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
DDRC = B00000001;  // set analog 0 to OUTPUT
PORTC = B00000001; //set analog0 to HIGH
Your comments (and assumptions) are wrong. Analog pins are INPUT only, by definition.

The analog pins can be used as digital pins, which is what you are doing here. The comments should reflect this,
Logged

Milan
Offline Offline
Edison Member
*
Karma: 2
Posts: 1128
gioblu.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Puls thanks for the answer, you you are right, sorry, misunderstanding.
Code:
DDRC = B00000001;  // use analog 0 as digital OUTPUT
PORTC = B00000001; //use analog 0 as digital set to HIGH
Ok it works I can see a LED on and off, seems works...

But, i can't understand why if I use the two lines shown before instead of:
Code:
pinMode(A0, OUTPUT);
digitalWrite(A0, HIGH);
My code don't works, i get null / crappy characters...

Is there some difference in the two codes shown??
I am killed by this different result...
« Last Edit: December 23, 2011, 11:06:51 pm by gbm » Logged

Community robotica / programmazione Arduino
www.gioblu.com

Germany
Offline Offline
Edison Member
*
Karma: 133
Posts: 1447
If you believe something is right, you won't see what's wrong (David Straker).
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi

My suggestion would be to use digitalPinToBitMask, portOutputRegister, portOutputRegister and digitalPinToPort.
It seems that these functions have been moved into the official API since Arduino 1.0 but are not yet documented. But their use is quite simple.

During setup, store important pins in some global variables:
Code:
uint8_t mask = digitalPinToBitMask(pin);
volatile uint8_t *out = portOutputRegister(digitalPinToPort(pin));

Then, you can set your output pin state very simple and fast throughout your code:
Code:
*out |= mask;

It is fast and you can use the usual pin numbers. Additionally it should be compatible with different Arduino Boards.

Oliver
Logged

0
Offline Offline
Edison Member
*
Karma: 63
Posts: 1604
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

A lot of work has been done on fast digital read/write. 

Using digitalPinToBitMask and portOutputRegister will not produce the fastest smallest code.

Here is a link to a smaller faster library http://code.google.com/p/digitalwritefast/downloads/list.

You will need to modify digitalWriteFast.h for Arduino 1.0  by changing this
Code:
#include "WProgram.h"
#include <wiring.h>
to this
Code:
#if ARDUINO >= 100
#include <Arduino.h>
#else
#include "WProgram.h"
#include <wiring.h>
#endif

I am working on alternate implementation that will include functions like digitalRead/digitalWrite and classes for fast read/write.  A preview of the classes is here http://arduino.cc/forum/index.php/topic,84044.0.html.  I am working on a better version and will post it soon.
Logged

Milan
Offline Offline
Edison Member
*
Karma: 2
Posts: 1128
gioblu.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Fatlib!! Are you the creator of fatlib library?!?!?  smiley-eek
Thank you for the answer, but I don't want to use another library and I need to optimize flash space, I only need the 2 assembly / c ansi commands to do the same operation of digitalWrite HIGH or LOW faster.
Logged

Community robotica / programmazione Arduino
www.gioblu.com

0
Offline Offline
Edison Member
*
Karma: 63
Posts: 1604
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can't beat digitalWriteFast for size or speed.

digitalWriteFast(pin, HIGH) compiles to a single sbi two byte instruction for all Arduino 328 pins when pin is a constant.   digitalWriteFast(pin, LOW) compiles to the two byte cbi instruction when pin is a constant.  These instructions execute in two cycles or 125 ns on a 16 MHz cpu.

High address pins on the Mega take more flash and execute in more cycles.

Yes I wrote a number of SD libraries for FAT file systems.
Logged

Milan
Offline Offline
Edison Member
*
Karma: 2
Posts: 1128
gioblu.com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

for this reason your advise is to include in my library also digitalwritefast?
Logged

Community robotica / programmazione Arduino
www.gioblu.com

0
Offline Offline
Edison Member
*
Karma: 63
Posts: 1604
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

digitalWriteFast has a lot of advantages.  It has a simple syntax that works on 328 and Mega Arduinos using pin numbers, not port names and bit names.

It is atomic so it works on a Mega when you access a pin on a port that has another pin with access from an interrupt routine.

This idea isn't atomic and uses a lot more flash:
Code:
  uint8_t mask = digitalPinToBitMask(pin);
  volatile uint8_t *out = portOutputRegister(digitalPinToPort(pin));
  *out |= mask;

If you want to play with low level access to the digital pins then DIY but you won't do better than digitalWriteFast and may have bugs.
Logged

Pages: [1]   Go Up
Jump to: