Pages: 1 [2] 3   Go Down
Author Topic: Manage ports?  (Read 3095 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 81
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As I mentioned I saw these functions in Wiring source. After testing them I put them in wiring_digital.c to make them built-in.

They works well in regular code also.  But you should add "false" after return of statement "if (inputregister == NOT_A_PORT) return;"
in portRead function.
Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 524
Posts: 26486
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

if (inputregister == NOT_A_PORT) return false;

Like that?
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.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

in the last 2 cases, what does
cli();
do?

He is protecting the port change from interrupts. So to comment it:

Code:
        uint8_t oldSREG = SREG;   // remember interrupt flag (and other flags)
cli();          // turn interrupts off
*portregister = val;    // do something, knowing interrupts won't occur
SREG = oldSREG;     // put interrupt flag back (set it again, if it was set before)
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

They works well in regular code also.  But you should add "false" after return of statement "if (inputregister == NOT_A_PORT) return;"
in portRead function.

You could return 0 (false is a bit misleading), but you can't tell the difference between supplying an invalid port (which returns zero) and reading a valid port, and them all being off (which returns zero).
Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 524
Posts: 26486
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

So what should this line be then?

if (inputregister == NOT_A_PORT) return;
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.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Since portRead is declared to return a byte (uint8_t) it seems reasonable to return a number in the range 0 to 255. (Returning true or false would be more reasonable if it was declared to return a boolean type).

A reasonable value would be 0, like this:

Code:
uint8_t portRead(uint8_t port)
{
volatile uint8_t *inputregister;

inputregister = portInputRegister(port);

if (inputregister == NOT_A_PORT) return 0;

uint8_t oldSREG = SREG;
cli();
uint8_t portValue = *inputregister;
SREG = oldSREG;
return portValue;
}

Bear in mind, as I said before, a return of 0 could either mean "not a port" or "it is a port and all bits are off".
Logged

Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 524
Posts: 26486
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

Okay, I changed my sample code to be return 0, altho hopefully I'll be awake enough when I write some code to use this to no try & access nonexistent ports.
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.

Guatemala
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I have mooched the port manipulation functions from wiring platform. Copy them into "wiring_digital.c" to have built-in port manipulation.

Functions
Code:
void portMode(uint8_t port, uint8_t mode)
{
volatile uint8_t *moderegister;

moderegister = portModeRegister(port);

if (moderegister == NOT_A_PORT) return;

uint8_t oldSREG = SREG;
cli();

//*moderegister = mode;
if (mode == OUTPUT)
*moderegister = 0xff;
else
*moderegister = 0x00;

SREG = oldSREG;
}

uint8_t portRead(uint8_t port)
{
volatile uint8_t *inputregister;

inputregister = portInputRegister(port);

if (inputregister == NOT_A_PORT) return;

uint8_t oldSREG = SREG;
cli();
uint8_t portValue = *inputregister;
SREG = oldSREG;
return portValue;
}

void portWrite(uint8_t port, uint8_t val)
{
volatile uint8_t *portregister;

portregister = portOutputRegister(port);

if (portregister == NOT_A_PORT) return;

uint8_t oldSREG = SREG;
cli();
*portregister = val;
SREG = oldSREG;
}

Example
Code:
void setup() {
  portMode(PD, OUTPUT);
}

void loop() {
  portWrite(PD, B0001000);
  delay(500);
  portWrite(PD, B0000000);
  delay(500);
}

Well... I can't understand this code smiley-eek
Logged


Guatemala
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

My Wiring_digital.c have this:

Code:
/*
  wiring_digital.c - digital input and output functions
  Part of Arduino - http://www.arduino.cc/

  Copyright (c) 2005-2006 David A. Mellis

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA

  Modified 28 September 2010 by Mark Sproul

  $Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/

#include "wiring_private.h"
#include "pins_arduino.h"

void pinMode(uint8_t pin, uint8_t mode)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *reg;

if (port == NOT_A_PIN) return;

// JWS: can I let the optimizer do this?
reg = portModeRegister(port);

if (mode == INPUT) {
uint8_t oldSREG = SREG;
                cli();
*reg &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
                cli();
*reg |= bit;
SREG = oldSREG;
}
}

// Forcing this inline keeps the callers from having to push their own stuff
// on the stack. It is a good performance win and only takes 1 more byte per
// user than calling. (It will take more bytes on the 168.)
//
// But shouldn't this be moved into pinMode? Seems silly to check and do on
// each digitalread or write.
//
// Mark Sproul:
// - Removed inline. Save 170 bytes on atmega1280
// - changed to a switch statment; added 32 bytes but much easier to read and maintain.
// - Added more #ifdefs, now compiles for atmega645
//
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
//static inline void turnOffPWM(uint8_t timer)
static void turnOffPWM(uint8_t timer)
{
switch (timer)
{
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A:   cbi(TCCR1A, COM1A1);    break;
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B:   cbi(TCCR1A, COM1B1);    break;
#endif

#if defined(TCCR2) && defined(COM21)
case  TIMER2:   cbi(TCCR2, COM21);      break;
#endif

#if defined(TCCR0A) && defined(COM0A1)
case  TIMER0A:  cbi(TCCR0A, COM0A1);    break;
#endif

#if defined(TIMER0B) && defined(COM0B1)
case  TIMER0B:  cbi(TCCR0A, COM0B1);    break;
#endif
#if defined(TCCR2A) && defined(COM2A1)
case  TIMER2A:  cbi(TCCR2A, COM2A1);    break;
#endif
#if defined(TCCR2A) && defined(COM2B1)
case  TIMER2B:  cbi(TCCR2A, COM2B1);    break;
#endif

#if defined(TCCR3A) && defined(COM3A1)
case  TIMER3A:  cbi(TCCR3A, COM3A1);    break;
#endif
#if defined(TCCR3A) && defined(COM3B1)
case  TIMER3B:  cbi(TCCR3A, COM3B1);    break;
#endif
#if defined(TCCR3A) && defined(COM3C1)
case  TIMER3C:  cbi(TCCR3A, COM3C1);    break;
#endif

#if defined(TCCR4A) && defined(COM4A1)
case  TIMER4A:  cbi(TCCR4A, COM4A1);    break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case  TIMER4B:  cbi(TCCR4A, COM4B1);    break;
#endif
#if defined(TCCR4A) && defined(COM4C1)
case  TIMER4C:  cbi(TCCR4A, COM4C1);    break;
#endif
#if defined(TCCR5A)
case  TIMER5A:  cbi(TCCR5A, COM5A1);    break;
case  TIMER5B:  cbi(TCCR5A, COM5B1);    break;
case  TIMER5C:  cbi(TCCR5A, COM5C1);    break;
#endif
}
}

void digitalWrite(uint8_t pin, uint8_t val)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *out;

if (port == NOT_A_PIN) return;

// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);

out = portOutputRegister(port);

if (val == LOW) {
uint8_t oldSREG = SREG;
                cli();
*out &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
                cli();
*out |= bit;
SREG = oldSREG;
}
}

int digitalRead(uint8_t pin)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);

if (port == NOT_A_PIN) return LOW;

// If the pin that support PWM output, we need to turn it off
// before getting a digital reading.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);

if (*portInputRegister(port) & bit) return HIGH;
return LOW;
}

void portMode(uint8_t port, uint8_t mode)
{
volatile uint8_t *moderegister;

moderegister = portModeRegister(port);

if (moderegister == NOT_A_PORT) return;

uint8_t oldSREG = SREG;
cli();

//*moderegister = mode;
if (mode == OUTPUT)
*moderegister = 0xff;
else
*moderegister = 0x00;

SREG = oldSREG;
}

uint8_t portRead(uint8_t port)
{
volatile uint8_t *inputregister;

inputregister = portInputRegister(port);

if (inputregister == NOT_A_PORT) return;

uint8_t oldSREG = SREG;
cli();
uint8_t portValue = *inputregister;
SREG = oldSREG;
return portValue;
}

void portWrite(uint8_t port, uint8_t val)
{
volatile uint8_t *portregister;

portregister = portOutputRegister(port);

if (portregister == NOT_A_PORT) return;

uint8_t oldSREG = SREG;
cli();
*portregister = val;
SREG = oldSREG;
}

now how to use it? :S

Well I tried to add it to regular code and it doesn't work... sends me a lot of errors :/ even if I put the functions on the C program...
« Last Edit: September 18, 2011, 08:57:37 pm by jrlc » Logged


Global Moderator
Boston area, metrowest
Online Online
Brattain Member
*****
Karma: 524
Posts: 26486
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

The example was given back reply #11

void setup() {
  portMode(PD, OUTPUT);  // sets the pins in Port D to be outputs
}

void loop() {
  portWrite(PD, B0001000);  //sets the Port D outputs to B00001000
  delay(500);
  portWrite(PD, B0000000);  //sets the Port D outputs to B00000000
  delay(500);
}
and I imagine that
byte variablePort = portRead (PD);
would read the port bit states into variablePort
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.

Guatemala
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The example was given back reply #11

void setup() {
  portMode(PD, OUTPUT);  // sets the pins in Port D to be outputs
}

void loop() {
  portWrite(PD, B0001000);  //sets the Port D outputs to B00001000
  delay(500);
  portWrite(PD, B0000000);  //sets the Port D outputs to B00000000
  delay(500);
}
and I imagine that
byte variablePort = portRead (PD);
would read the port bit states into variablePort


yes, I copied that and added the functions but it sends me a lot of errors.

I copied into the c progrman under the void loop function

also I copied into the wiring_digital.c but it still sending me errors...
Logged


0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 81
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry my fault you also have to put function prototypes in "Arduino.h".
Function prototypes are;
Code:
void portMode(uint8_t port, uint8_t mode);
uint8_t portRead(uint8_t port);
void portWrite(uint8_t port, uint8_t val);
Logged

Offline Offline
Edison Member
*
Karma: 19
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

How is
Code:
value = portRead(PB);
different from  
Code:
value = PINB;

besides being a lot slower to execute? Pretty much the same thing for the other two.

Edit: fixing code tags...
« Last Edit: September 19, 2011, 07:14:37 pm by WizenedEE » Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 81
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@WizenedEE

Yes you are right, direct hardware usage is always faster than prototype functions.  But most of Arduino users including me have not electronic background. For us really hard to understand MCU hardware basics. And the aim of Arduino platform is to make the usage of microcontroller easier to everyone. IMO with these port functions every Arduino user can easily use the ports.
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 126
Posts: 8473
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think there are some potential gotchas with this code

Code:
uint8_t oldSREG = SREG;
cli();
uint8_t portValue = *inputregister;
SREG = oldSREG;
return portValue;

What if you get an interrupt after you save SREG but before the cli()? I think you should swap those two lines.

And what if you get one that modifies the port after the SREG restore but before the return? In this case I guess it's essentially the same as a port changing state just after you read it so maybe no harm done.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

Pages: 1 [2] 3   Go Up
Jump to: