Go Down

Topic: Use of direct port register to set PIN state without digitalWrite - Help needed (Read 2582 times) previous topic - next topic

gbm

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: [Select]
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: [Select]
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.
Community robotica / programmazione Arduino
www.gioblu.com

CrossRoads

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.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

gbm

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: [Select]
int BITreading = PINC & (1<<B00000000);

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


I try like this:
Code: [Select]
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?
Community robotica / programmazione Arduino
www.gioblu.com

PaulS

Code: [Select]
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,

gbm

Hi Puls thanks for the answer, you you are right, sorry, misunderstanding.
Code: [Select]
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: [Select]
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...
Community robotica / programmazione Arduino
www.gioblu.com

olikraus

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: [Select]

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: [Select]

*out |= mask;


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

Oliver

fat16lib

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: [Select]

#include "WProgram.h"
#include <wiring.h>

to this
Code: [Select]

#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.

gbm

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.
Community robotica / programmazione Arduino
www.gioblu.com

fat16lib

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.

gbm

for this reason your advise is to include in my library also digitalwritefast?
Community robotica / programmazione Arduino
www.gioblu.com

fat16lib

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: [Select]

  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.

Go Up