We all know the 595 shift registers and the arduino "shiftOut" function. Lets imagine you have the same thing, but with 64 Outputs and different polarity. I'm trying to make a libary to control a 64bit shitregister.
If i use "digitalWrite(x,x)" for this, the shifting progress is way to slow, so its not an option. I've implemented the following function:
#define thePort PORTD //define Hardware port where Shift-Registers are connected
#define DATA PD5 //define Dataline
#define OE 6 //define latch pin
#define CLK PD7 //define clockline
void setOutputs(unsigned long val_one, unsigned long val_two) { //Function to shift out 2 x 32bit fast void setOutputs(unsigned long val_one, unsigned long val_two) { //Function to shift out 2 x 32bit fast enough to prevent flicker!
// ------------WARNING!--------------------
// This functions operates directly on ports, not via digitalWrite()
// because digitalWrite() would be to slow, and display would flicker
// if different pins are used, you maybe hav to change the variable "thePort"
// to the matching I/O port letter of the controller!
digitalWrite(OE, LOW); //Disable Outputs to prevent flicker
//Send first 32-bit variable value
for (int i = 0; i < 32; i++) {
thePort &= ~_BV(DATA); //Data LOW
if ( bitRead(val_one, i) == 1) {
thePort |= _BV(DATA); //Data HIGH
}
thePort |= _BV(CLK); //CLK HIGH
thePort &= ~_BV(CLK); //CLK LOW
}
//Send second 32-bit variable value
for (int i = 0; i < 32; i++) {
thePort &= ~_BV(DATA); //Data LOW
if ( bitRead(val_two, i) == 1) {
thePort |= _BV(DATA); //Data HIGH
}
thePort |= _BV(CLK); //CLK HIGH
thePort &= ~_BV(CLK); //CLK LOW
}
digitalWrite(OE, HIGH); //Enable Outputs
}
This function works fine, but relys on a defined port and pin instead of a library call.
I looked at the digitalWrite code - here is what happens:
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);
uint8_t oldSREG = SREG;
cli();
if (val == LOW) {
*out &= ~bit;
} else {
*out |= bit;
}
SREG = oldSREG;
}
Now my approach was to only run the conversion to port once and save the port, i tied the following:
lib.h
class HVSR {
public:
HVSR(uint8_t clkPin, uint8_t dataPin, uint8_t enPin);
void setOutputs(uint32_t firstv, uint32_t secondv);
private:
volatile uint8_t *theDataPort;
volatile uint8_t *theClkPort;
uint8_t theDataPin;
uint8_t theClkPin;
uint8_t theEnPin;
};
constructor
HVSR::HVSR(uint8_t clkPin, uint8_t dataPin, uint8_t enPin){
//***
//***Set pin states***********
pinMode(clkPin,OUTPUT); //Set Clock-Pin to Output
pinMode(dataPin,OUTPUT); //Set Data-Pin to Output
pinMode(enPin,OUTPUT); //Set Chip-Enable-Pin to Output
//***Convert pins to MCU native values for fast shifting****
theClkPort = portOutputRegister(digitalPinToPort(clkPin)); //get the port of the given pin
theDataPort = portOutputRegister(digitalPinToPort(dataPin)); //get the port of the given pin
theClkPin = digitalPinToBitMask(clkPin); //get the bit of the selected pin
theDataPin = digitalPinToBitMask(dataPin); //get the bit of the selected pin
theEnPin=enPin;
digitalWrite(enPin,HIGH);
}
shift function
void HVSR::setOutputs(uint32_t firstv, uint32_t secondv){
cli();
digitalWrite(theEnPin, LOW); //Disable Outputs to prevent flicker
//Send first 32-bit variable value
for (int i = 0; i < 32; i++) {
theDataPort &= ~_BV(theDataPin); //Data LOW
if ( bitRead(firstv, i) == 1) {
theDataPort |= _BV(theDataPin); //Data HIGH
}
theClkPort |= _BV(theClkPin); //CLK HIGH
theClkPort &= ~_BV(theClkPin); //CLK LOW
}
//Send second 32-bit variable value
for (int i = 0; i < 32; i++) {
theDataPort &= ~_BV(theDataPin); //Data LOW
if ( bitRead(secondv, i) == 1) {
theDataPort |= _BV(theDataPin); //Data HIGH
}
theClkPort |= _BV(theClkPin); //CLK HIGH
theClkPort &= ~_BV(theClkPin); //CLK LOW
}
digitalWrite(theEnPin, HIGH); //Enable Outputs
sei();
}
i tried to copy the content of the digitalWrite() to my own lib, but sadly i cant compile. I'm getting the following errors (multiple, but only posted here)
..\HVShift.cpp:63:15: error: in evaluation of 'operator|=(volatile uint8_t* {aka volatile unsigned char*}, int)'
..\HVShift.cpp:64:15: error: invalid operands of types 'volatile uint8_t* {aka volatile unsigned char*}' and 'int' to binary 'operator&'
theClkPort &= ~_BV(theClkPin); //CLK LOW
Has anyone here an idea how to fix and explain me what i'm doing wrong?