268 lines
6.9 KiB
C++
268 lines
6.9 KiB
C++
|
// ---------------------------------------------------------------------------
|
||
|
// Created by Florian Fida on 20/01/12
|
||
|
// Copyright 2012 - Under creative commons license 3.0:
|
||
|
// Attribution-ShareAlike CC BY-SA
|
||
|
// http://creativecommons.org/licenses/by-sa/3.0/
|
||
|
//
|
||
|
// This software is furnished "as is", without technical support, and with no
|
||
|
// warranty, express or implied, as to its usefulness for any purpose.
|
||
|
// ---------------------------------------------------------------------------
|
||
|
// fio_shiftOut1 functions are based on Shif1 protocol developed by Roman Black
|
||
|
// (http://www.romanblack.com/shift1.htm)
|
||
|
//
|
||
|
// Thread Safe: No
|
||
|
// Extendable: Yes
|
||
|
//
|
||
|
// @file FastIO.h
|
||
|
// This file implements basic fast IO routines.
|
||
|
//
|
||
|
// @brief
|
||
|
//
|
||
|
// @version API 1.0.0
|
||
|
//
|
||
|
// @author Florian Fida -
|
||
|
//
|
||
|
// 2012-03-16 bperrybap updated fio_shiftout() to be smaller & faster
|
||
|
//
|
||
|
// @todo:
|
||
|
// support chipkit:
|
||
|
// (https://github.com/chipKIT32/chipKIT32-MAX/blob/master/hardware/pic32/
|
||
|
// cores/pic32/wiring_digital.c)
|
||
|
// ---------------------------------------------------------------------------
|
||
|
#include "FastIO.h"
|
||
|
|
||
|
|
||
|
fio_register fio_pinToOutputRegister(uint8_t pin, uint8_t initial_state)
|
||
|
{
|
||
|
pinMode(pin, OUTPUT);
|
||
|
|
||
|
if(initial_state != SKIP)
|
||
|
{
|
||
|
digitalWrite(pin, initial_state); // also turns off pwm timer
|
||
|
}
|
||
|
#ifdef FIO_FALLBACK
|
||
|
// just wasting memory if not using fast io...
|
||
|
return 0;
|
||
|
#else
|
||
|
return portOutputRegister(digitalPinToPort(pin));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
fio_register fio_pinToInputRegister(uint8_t pin)
|
||
|
{
|
||
|
pinMode(pin, INPUT);
|
||
|
digitalWrite(pin, LOW); // also turns off pwm timer and pullup
|
||
|
#ifdef FIO_FALLBACK
|
||
|
// just wasting memory if not using fast io...
|
||
|
return 0;
|
||
|
#else
|
||
|
return portInputRegister(digitalPinToPort(pin));
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
fio_bit fio_pinToBit(uint8_t pin)
|
||
|
{
|
||
|
#ifdef FIO_FALLBACK
|
||
|
// (ab)use the bit variable to store the pin
|
||
|
return pin;
|
||
|
#else
|
||
|
return digitalPinToBitMask(pin);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void fio_digitalWrite(fio_register pinRegister, fio_bit pinBit, uint8_t value)
|
||
|
{
|
||
|
#ifdef FIO_FALLBACK
|
||
|
digitalWrite(pinBit, value);
|
||
|
#else
|
||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||
|
{
|
||
|
if(value == LOW)
|
||
|
{
|
||
|
fio_digitalWrite_LOW(pinRegister,pinBit);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fio_digitalWrite_HIGH(pinRegister,pinBit);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
int fio_digitalRead(fio_register pinRegister, uint8_t pinBit)
|
||
|
{
|
||
|
#ifdef FIO_FALLBACK
|
||
|
return digitalRead (pinBit);
|
||
|
#else
|
||
|
if (*pinRegister & pinBit)
|
||
|
{
|
||
|
return HIGH;
|
||
|
}
|
||
|
return LOW;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void fio_shiftOut (fio_register dataRegister, fio_bit dataBit,
|
||
|
fio_register clockRegister, fio_bit clockBit,
|
||
|
uint8_t value, uint8_t bitOrder)
|
||
|
{
|
||
|
// # disable interrupts
|
||
|
int8_t i;
|
||
|
|
||
|
if(bitOrder == LSBFIRST)
|
||
|
{
|
||
|
for(i = 0; i < 8; i++)
|
||
|
{
|
||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||
|
{
|
||
|
if(value & 1)
|
||
|
{
|
||
|
fio_digitalWrite_HIGH(dataRegister, dataBit);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fio_digitalWrite_LOW(dataRegister, dataBit);
|
||
|
}
|
||
|
value >>= 1;
|
||
|
fio_digitalWrite_HIGH (clockRegister, clockBit);
|
||
|
fio_digitalWrite_LOW (clockRegister,clockBit);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for(i = 0; i < 8; i++)
|
||
|
{
|
||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||
|
{
|
||
|
if(value & 0x80)
|
||
|
{
|
||
|
fio_digitalWrite_HIGH(dataRegister, dataBit);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fio_digitalWrite_LOW(dataRegister, dataBit);
|
||
|
}
|
||
|
value <<= 1;
|
||
|
fio_digitalWrite_HIGH (clockRegister, clockBit);
|
||
|
fio_digitalWrite_LOW (clockRegister,clockBit);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void fio_shiftOut(fio_register dataRegister, fio_bit dataBit,
|
||
|
fio_register clockRegister, fio_bit clockBit)
|
||
|
{
|
||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||
|
{
|
||
|
// shift out 0x0 (B00000000) fast, byte order is irrelevant
|
||
|
fio_digitalWrite_LOW (dataRegister, dataBit);
|
||
|
|
||
|
for(uint8_t i = 0; i<8; ++i)
|
||
|
{
|
||
|
fio_digitalWrite_HIGH (clockRegister, clockBit);
|
||
|
fio_digitalWrite_SWITCH (clockRegister, clockBit);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void fio_shiftOut1_init(uint8_t pin)
|
||
|
{
|
||
|
fio_shiftOut1_init(fio_pinToOutputRegister(pin,HIGH),fio_pinToBit(pin));
|
||
|
}
|
||
|
|
||
|
void fio_shiftOut1_init(fio_register shift1Register, fio_bit shift1Bit)
|
||
|
{
|
||
|
// Make sure that capacitors are charged
|
||
|
// 300us is an educated guess...
|
||
|
fio_digitalWrite(shift1Register,shift1Bit,HIGH);
|
||
|
delayMicroseconds(300);
|
||
|
}
|
||
|
|
||
|
|
||
|
void fio_shiftOut1(fio_register shift1Register, fio_bit shift1Bit, uint8_t value,
|
||
|
boolean noLatch)
|
||
|
{
|
||
|
/*
|
||
|
* this function are based on Shif1 protocol developed by Roman Black
|
||
|
* (http://www.romanblack.com/shift1.htm)
|
||
|
*
|
||
|
* test sketches:
|
||
|
* http://pastebin.com/raw.php?i=2hnC9v2Z
|
||
|
* http://pastebin.com/raw.php?i=bGg4DhXQ
|
||
|
* http://pastebin.com/raw.php?i=tg1ZFiM5
|
||
|
* http://pastebin.com/raw.php?i=93ExPDD3 - cascading
|
||
|
* tested with:
|
||
|
* TPIC6595N - seems to work fine (circuit: http://www.3guys1laser.com/
|
||
|
* arduino-one-wire-shift-register-prototype)
|
||
|
* 7HC595N
|
||
|
*/
|
||
|
|
||
|
// iterate but ignore last bit (is it correct now?)
|
||
|
for(int8_t i = 7; i>=0; --i)
|
||
|
{
|
||
|
|
||
|
// assume that pin is HIGH (smokin' pot all day... :) - requires
|
||
|
// initialization
|
||
|
if(value & _BV(i))
|
||
|
{
|
||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||
|
{
|
||
|
// HIGH = 1 Bit
|
||
|
fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,LOW);
|
||
|
//hold pin LOW for 1us - done! :)
|
||
|
fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,HIGH);
|
||
|
} // end critical section
|
||
|
//hold pin HIGH for 15us
|
||
|
delayMicroseconds(15);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||
|
{
|
||
|
// LOW = 0 Bit
|
||
|
fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,LOW);
|
||
|
// hold pin LOW for 15us
|
||
|
delayMicroseconds(15);
|
||
|
fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,HIGH);
|
||
|
} // end critical section
|
||
|
|
||
|
// hold pin HIGH for 30us
|
||
|
delayMicroseconds(30);
|
||
|
}
|
||
|
if(!noLatch && i==1)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!noLatch)
|
||
|
{
|
||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||
|
{
|
||
|
// send last bit (=LOW) and Latch command
|
||
|
fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,LOW);
|
||
|
} // end critical section
|
||
|
delayMicroseconds(199); // Hold pin low for 200us
|
||
|
|
||
|
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||
|
{
|
||
|
fio_digitalWrite_HIGH(shift1Register,shift1Bit);
|
||
|
} // end critical section
|
||
|
delayMicroseconds(299); // Hold pin high for 300us and leave it that
|
||
|
// way - using explicit HIGH here, just in case.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void fio_shiftOut1(uint8_t pin, uint8_t value, boolean noLatch)
|
||
|
{
|
||
|
fio_shiftOut1(fio_pinToOutputRegister(pin, SKIP),fio_pinToBit(pin),value, noLatch);
|
||
|
}
|