I'm trying to control a parallel LCD with a 595 shift register, and control >that< 595 with another 595, and using some of my leftover outputs on the second 595 to control a 597 (I'm low on pins...).
So, dissatisfied with code like:
void shiftout(void)
{
uint8_t mask=1;
for (int i=0; i<8; i++) {
if ((outbyte & mask)==0)
digitalWrite(dpin, LOW);
else
digitalWrite(dpin, HIGH);
HL(dclk); // Toggle clockpin.
}
HL(dlat); // Toggle latchpin
}
because of the massive overhead that comes along with digitalWrite, I decided to try in assembly.
(Oh, this code worked just fine, but was only able to output about 2 characters per millisecond, or 20kbps. Waaay to slow for an isr...)
I wrote:
void shiftout_asm(void)
{
asm volatile (
"SBI %[datport], %[datbit]" "\n\t" // digital write HIGH
"SBRS %[outb], 0" "\n\t" // is bit 0 set?
"CBI %[datport], %[datbit]" "\n\t" // No. dW low...
"SBI %[clkport], %[clockbit]" "\n\t" // Clock high
"CBI %[clkport], %[clockbit]" "\n\t" // and low..
"SBI %[datport], %[datbit]" "\n\t" // digital write HIGH
"SBRS %[outb], 1" "\n\t" // is bit 1 set?
"CBI %[datport], %[datbit]" "\n\t" // No. dW low...
"SBI %[clkport], %[clockbit]" "\n\t" // Clock high
"CBI %[clkport], %[clockbit]" "\n\t" // and low..
// ... rinse and repeat for bits 2-6 code ommitted for brevity
"SBI %[datport], %[datbit]" "\n\t" // digital write HIGH
"SBRS %[outb], 7" "\n\t" // is bit 7 set?
"CBI %[datport], %[datbit]" "\n\t" // No. dW low...
"SBI %[clkport], %[clockbit]" "\n\t" // Clock high
"CBI %[clkport], %[clockbit]" "\n\t" // and low..
"SBI %[latport], %[latpin]" "\n\t" // latch high
"SBI %[latport], %[latpin]" "\n\t" // And low, and we're
// shifted and happy.
: // no output operands
: [datport] "I" (_SFR_IO_ADDR(PORTD)), [datbit] "I" (6), //PIN6
[clkport] "I" (_SFR_IO_ADDR(PORTD)), [clkbit] "I" (3), //PIN3
[latport] "I" (_SFR_IO_ADDR(PORTD)), [clkbit] "I" (7), //PIN7
[outb] "r" (outbyte)
: // No clobbers
);
}
And, after several hours of compiler-fighting, got it to work. Much more impressive, with upwards of 25kCPS, 250kbps...
If I stick this:
volatile uint8_t *data_port=&PORTD;
and the corresponding SFR in the input operands section to:
_SFR_IO_ADDR(*data_port)
It compiles and works fine.
However, if I move the definition of uint8_t data_port to global scope, it won't compile.
I get an "impossible constraint in ASM" error with the input operand that is defined at global scope.
I've not investigated this a great deal, but I can't even pass one of the immediate values (the pin numbers) if they're in variables declared at global scope.
This forum request for help may be a bit premature, but I'm on vacation, and this is driving me batty, trying to figure this out with awful wireless in hotels in Oregon.
Anyone been through this have an "Oh! Here's what you need to do" to throw at me?
Thanks.
