Pushing 1 byte value (the 8 bits) over 2 ports (because on arduino uno no full 8

Hi,

I wrote some code which reads info from sd card and the purpose is that the arduino should now be able to output the 8 bits to portpins on the atmega328 from the arduino uno.

As far as I can see (I use the SPI pins for the SD reading and I also use TX and RX for some other part of the code + I might use INT0 later on) the only pins left are

PC0 AVR pin 23
PC1 AVR pin 24
PC2 AVR pin 25
PC3 AVR pin 26
PC4 AVR pin 27
PC5 AVR pin 28

PD3 AVR pin 5
PD4 AVR pin 6
PD5 AVR pin 11
PD6 AVR pin 12
PD7 AVR pin 13
PB0 AVR pin 14

I have to push the 8 bits data over 8 of these pins

Looking at the available pins, I would guess that it could be interesting to output 6 of the 8 bits on PC0->PC5 and then maybe the other 2 bits to PD6->PD7

But can somebody help me a little by saying how I could do this?

I guess I need to do something like

[pseudocode below]
IF (bit1=1) {digitalWrite(portC0pin,HIGH); // send 1}
ELSE{digitalWrite(portC0pin,LOW); // send 0}
IF (bit2=1) {digitalWrite(portC1pin,HIGH); // send 1}
ELSE{digitalWrite(portC1pin,LOW); // send 0}
IF (bit3=1) {digitalWrite(portC2pin,HIGH); // send 1}
ELSE{digitalWrite(portC2pin,LOW); // send 0}
IF (bit4=1) {digitalWrite(portC3pin,HIGH); // send 1}
ELSE{digitalWrite(portC3pin,LOW); // send 0}
IF (bit5=1) {digitalWrite(portC4pin,HIGH); // send 1}
ELSE{digitalWrite(portC4pin,LOW); // send 0}
IF (bit6=1) {digitalWrite(portC5pin,HIGH); // send 1}
ELSE{digitalWrite(portC5pin,LOW); // send 0}
IF (bit7=1) {digitalWrite(portD6pin,HIGH); // send 1}
ELSE{digitalWrite(portD6pin,LOW); // send 0}
IF (bit8=1) {digitalWrite(portD7pin,HIGH); // send 1}
ELSE{digitalWrite(portD7pin,LOW); // send 0}

But how can I quickly check if a certain bit it set or not in a byte variable ?

Also, I guess I'll better setup a faster digitalWrite then the standard arduino built in function, since I read somewhere that digitalWrite can take upto 200 cpu cycles where a direct port pin manipulation is a lot faster?

Any help, hints would be very appreciated.

Kind regards and thanks,

Bart

look up direct port manipulation in the play ground, there is enough to get you started and a few clear warnings about what not to do.

You might be better off using an external shift register, it will save you some pins and you can send it a byte at a time rather than mapping bytes across two ports, look up shift register for lots of examples, it can be very fast as well so i dont see any down side.

Duane B
rcarduino.blogspot.com

The port manipulation is something I allready studied and it looks like fastest way to do is by using

PORTD |=_BV(2); // set port D pin 2
PORTD &= ~_BV(2); // reset port D pin 2
PIND |=_BV(2); // toggle port D pin 2

I could indeed shift out using a 74HC595 (cheap stuff) but I wonder what would be the fastest. With a 74HC595 you have to serially shift out bit for bit and with the port system you have so (more or less in a serial way) set 8 pins

Maybe I should check both and see which one is fastest.
Shifting out is built-in in arduino, but I wonder if that function doesn't have the same slowness like digitalwrite with code overhead. if I would have to shift out myself using direct port/pin access, then I could as well set the pins on the AVR and use that (saving 1 shift register).

My biggest concern for now if how I can fastest was check if a particular bit is set ....

For example if my variable is called myValue

Then how do I check if bit 3 is set? Would this be about the fastest code?

if (myValue & 0b00000001) { PORTC |=_BV(0); //set portC.0 }
else { PORTC &= ~_BV(0); //reset portC.0 }
if (myValue & 0b00000010) { PORTC |=_BV(1); //set portC.1 }
else { PORTC &= ~_BV(1); //reset portC.1 }
if (myValue & 0b00000100) { PORTC |=_BV(2); //set portC.2 }
else { PORTC &= ~_BV(2); //reset portC.2 }
if (myValue & 0b00001000) { PORTC |=_BV(3); //set portC.3 }
else { PORTC &= ~_BV(3); //reset portC.3 }
if (myValue & 0b00010000) { PORTC |=_BV(4); //set portC.4 }
else { PORTC &= ~_BV(4); //reset portC.4 }
if (myValue & 0b00100000) { PORTC |=_BV(5); //set portC.5 }
else { PORTC &= ~_BV(5); //reset portC.5 }
if (myValue & 0b01000000) { PORTD |=_BV(6); //set portD.6 }
else { PORTD &= ~_BV(6); //reset portD.6 }
if (myValue & 0b10000000) { PORTD |=_BV(7); //set portD.7 }
else { PORTD &= ~_BV(7); //reset portD.7 }

Of could I also set all pins to low and then run my ifs ?
like

PORTC &= ~_BV(0); //reset portC.0
PORTC &= ~_BV(1); //reset portC.1
PORTC &= ~_BV(2); //reset portC.2
PORTC &= ~_BV(3); //reset portC.3
PORTC &= ~_BV(4); //reset portC.4
PORTC &= ~_BV(5); //reset portC.5
PORTD &= ~_BV(6); //reset portD.6
PORTD &= ~_BV(7); //reset portD.7

if (myValue & 0b00000001) { PORTC |=_BV(0); //set portC.0 }
if (myValue & 0b00000010) { PORTC |=_BV(1); //set portC.1 }
if (myValue & 0b00000100) { PORTC |=_BV(2); //set portC.2 }
if (myValue & 0b00001000) { PORTC |=_BV(3); //set portC.3 }
if (myValue & 0b00010000) { PORTC |=_BV(4); //set portC.4 }
if (myValue & 0b00100000) { PORTC |=_BV(5); //set portC.5 }
if (myValue & 0b01000000) { PORTD |=_BV(6); //set portD.6 }
if (myValue & 0b10000000) { PORTD |=_BV(7); //set portD.7 }

I would guess that both these ways are very fast ?

Maybe I could get the zeroing of the pins faster?

If only I could quickly set portc pins 0->5 to LOW without affecting pinc.6 and pinc.7 (because I may not alter shose)
and then the same with portd pin 6 and 7 (without altering the others)

I guess it might be possible by doing a boolean AND with 0b00111111 for port C, but can anyone please tell me how I should type this in code ?

so the line to set bits 0->5 of port C to LOW without affecting pinc.6 and pinc.7

Kind regards,

Bart

I have no idea what your project is but my guess is that you might be wasting your time on things that have no impact on the final project.

I would suggest go with a shift register, I am sure there are fast libraries for it, people use them to drive vast arrays of LEDs quicker than the human eye can see so speed really is not going to be a problem.

A simple function interface such as a fast shift register library is much easier to work with in the long term than messing around with bit fiddling.

The shift register keeps more pins free so you can expand your project with new and interesting features in the future.

Its good advice, but its free so you might think its worth what you paid.

Duane B

rcarduino.blogspot.com

I understand what you mean, but I just wanted to make clear that the pins are there and will never be used anymore.

The chip only does this. It reads 512 bytes from an SD card and then myst be able to send them very quickly out byte over a 8 bits connection.

I do have to be able to achieve at least a speed of 250000 bytes per second, so thats 2 megabits. I guess thats quite fast for a 16mHz controller so I really wonder how I could do this best.

Possibly with thift register. I should maybe try this and time the speed of execution.

250000 bytes per second seems FAST, but I guess my project won't go over around 100000 per sec after all, so I just oversize currently

educa:
I understand what you mean, but I just wanted to make clear that the pins are there and will never be used anymore.

The chip only does this. It reads 512 bytes from an SD card and then myst be able to send them very quickly out byte over a 8 bits connection.

I do have to be able to achieve at least a speed of 250000 bytes per second, so thats 2 megabits. I guess thats quite fast for a 16mHz controller so I really wonder how I could do this best.

Possibly with thift register. I should maybe try this and time the speed of execution.

250000 bytes per second seems FAST, but I guess my project won't go over around 100000 per sec after all, so I just oversize currently

A shift register is never going to be faster than 8 direct pins. Use 8 pins from a single port and just write out each byte. Be more specific as to what your trying to do?

ok let me try to explain.

I am creating a cnc laser cutter machine.
That machine will interprete certain instructions (gcodes) to move a laserhead.
For standard movements this is not so much data, since you always have 1 byte which defines the instruction (what to do) + 2 x 2 bytes which define 2 word values (x and y coordinates to move to).
So 1 movement is 5 bytes (+ maybe some overhead)

Sometimes the machine has to travel very very fast (read 25000 steps per second upto 50000 steps). therefore, I have to be able to read data from the SD card fast enough to NEVER have to wait for the sd read to finish. In cnc applications a unexpected delay is a disaster for stepper motors, especially at high speeds.

So.... I was thinking like this.... I can blockread a buffer of 512 bytes from the SD card in aproximately 2ms. During those 2 ms I am aware of the fact that I better leave the arduino chip alone and not ask extra stuff. It will make stuff more complex and certainly reduce the speed for reading the SD buffer of 512 bytes.

Once you read the 512 bytes in 2ms time, then it would be nice if you could also transfer these bytes to another AVR chip (preferably parallell for speed) in 2 ms. 2ms = 2000µs so, 2000 / 512 = +- 4 µs

4µs = 64 clock cycles so I wonder if I can push out 1 byte value in 64 clock cycles, but even in the case of 128 cycles, I would still be able to push 125000kbyte/sec

because the reading of 512 bytes takes 2ms , I can not continuesly read data from the SD, so I would use 2 SD cards and 2 atmega328 chips and act like the following

STEP 1) LET CARD 1 READ 512 bytes in buffer

STEP 2) LET CARD 2 READ 512 bytes in buffer

and then REPEATEDLY read 512 bytes from the first card followed by 512 bytes from 2nd card. In the time that I am querying card 2 fro data, card1 can read in another block of 512 bytes.

It sounds a little strange at first , but it means you let 1 card read from SD to ram while you get fdata from the other card (which is allready in ram). That way you never have to wait for data and it always comes at aproximately the same speed.

Of course I could also use SERIAL communication and not use SD cards, but a PC to send the data, but then I would have to establish a 1mbits connection to get around 100000kb/sec and be able to push that out the pins, but I really wonder if that would be a relyable solution, since uart data seems to be auto-buffered by the arduino (so i guess with some prebuilt code built-in arduino environment) and there I don't know how efficient that would be.

100000 kbytes / sec is certainly the absolute minimum I should have to achieve not to loose steps in my software.

I think the SD card trick would be the most reliable since you don't even need to play with interrupts. You just first read 512 bytes and then push them out and because you have 2 identical circuits doing this you are sure that you have no waittime.

Maybe I should write another question. The arduino uno works on a atmega328p and that chip by default has only 28 pins and if you use what I use , then there is not a full port available anymore (only large portion of C and some of D)

But.... I see that there also exist atmega32 40pin chips. I wonder if that could provide me 1 full port, but I don't know if you can upload arduino bootloader to such devices.

You are probably onto something there, there is also the Mega and half a dozen other variants of Arduino

Duane

rcarduino.blogspot.com

I actually wonder

if I have my 8 bits value sitting in a byte variable myValue

Like for example 0b10101010

then I have to send the first 2 bits to PortD.7 and PortD.6 and then the other 6 bits to PortC.5 -> PortC.0

I could prepare 2 other byte vars to separate these

valueForPortD = myValue & 0b11000000
valueForPortC = myValue & 0b00111111

But can I then somehow set PORT D so that it only changes these 2 highest bits and don't touch the rest?

I mean could I do that by some kind of direct port manipulation on the port in its whole ?

If I could do that and change portC so that its lower 6 bits are changed to the lower 6 bits of myValue, but the higher 2 bits are untoched, then my problem would be solved in the fastest way, but is this possible in arduino ?

Help?

educa:
I actually wonder

if I have my 8 bits value sitting in a byte variable myValue

Like for example 0b10101010

then I have to send the first 2 bits to PortD.7 and PortD.6 and then the other 6 bits to PortC.5 -> PortC.0

I could prepare 2 other byte vars to separate these

valueForPortD = myValue & 0b11000000
valueForPortC = myValue & 0b00111111

But can I then somehow set PORT D so that it only changes these 2 highest bits and don't touch the rest?

I mean could I do that by some kind of direct port manipulation on the port in its whole ?

If I could do that and change portC so that its lower 6 bits are changed to the lower 6 bits of myValue, but the higher 2 bits are untoched, then my problem would be solved in the fastest way, but is this possible in arduino ?

Help?

Your looking for speed breaking things into multiple ports will probably not help. The biggest arduino IDE compatible is the 1284 that comes in a pdip form factor. It has a good deal more pins and sram. If your looking to send the data to another arduino why not just use SPI you just need one more pin to act as the chip select for the other arduino and it's the fastest method to move data the arduino has.

problem is the hardware SPI is allready used by the sd card

Just outputing the value with shiftout seemed like it is not fast enough.

I used fast port/pin manipulation to turn the latch pin low and then high again after the shift and in between I used 1 shiftOut call.

the result was that the complete time to shift out 1 byte was a little bit more then 0.12 milliseconds.

Sure thats fast, but thats only +- 8300 bytes/sec so useless for me.

Now I'll test shifting out with my own routines (fast port access)

I wrote my own function to shift out fast to a 74HC595

When I use the code below, then I use direct port access to push out byte values 0-> 255 over the datapin at quite high speeds.

1 full byte is sent in aproximately 5.5 microseconds, making an average transfer speed of 181800 bytes/sec possible

int latchPin = 8;
// latchpin is portb.0
int clockPin = 12;
//clock is portb.4
int dataPin = 11;
// data is portb.3

void setup() {
  //set pins to output so you can control the shift register
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  digitalWrite(latchPin, HIGH);
  delay(500);
  digitalWrite(latchPin, LOW);
  delay(500); //just some init code to see easier on logic analyser when the code starts after a reset
  cli();
}

void loop() {
  for (int myValue = 0; myValue < 256; myValue++) {

 PORTB &= ~_BV(0);   // reset latchpin

if (myValue & 0b10000000)  { PORTB |=_BV(3); }//set datapin  
   else { PORTB &= ~_BV(3); }//reset datapin

   PORTB |=_BV(4);     // Give 1 clock pulse
   PORTB &= ~_BV(4);   

if (myValue & 0b01000000)  { PORTB |=_BV(3); }//set datapin  
   else { PORTB &= ~_BV(3); }//reset datapin

   PORTB |=_BV(4);     // Give 1 clock pulse
   PORTB &= ~_BV(4);   

if (myValue & 0b00100000)  { PORTB |=_BV(3); }//set datapin
   else { PORTB &= ~_BV(3); }//reset datapin

   PORTB |=_BV(4);     // Give 1 clock pulse
   PORTB &= ~_BV(4);   

if (myValue & 0b00010000)  { PORTB |=_BV(3); }//set datapin
   else { PORTB &= ~_BV(3); }//reset datapin

   PORTB |=_BV(4);     // Give 1 clock pulse
   PORTB &= ~_BV(4);   

if (myValue & 0b00001000)  { PORTB |=_BV(3); }//set datapin
   else { PORTB &= ~_BV(3); }//reset datapin

   PORTB |=_BV(4);     // Give 1 clock pulse
   PORTB &= ~_BV(4);   

if (myValue & 0b00000100)  { PORTB |=_BV(3); }//set datapin
   else { PORTB &= ~_BV(3); }//reset datapin

   PORTB |=_BV(4);     // Give 1 clock pulse
   PORTB &= ~_BV(4);   

if (myValue & 0b00000010)  { PORTB |=_BV(3); }//set datapin
   else { PORTB &= ~_BV(3); }//reset datapin

   PORTB |=_BV(4);     // Give 1 clock pulse
   PORTB &= ~_BV(4);   

if (myValue & 0b00000001)  { PORTB |=_BV(3); }//set datapin
   else { PORTB &= ~_BV(3); }//reset datapin

   PORTB |=_BV(4);     // Give 1 clock pulse
   PORTB &= ~_BV(4);   

   PORTB |=_BV(0);     // set latchpin
  }
}

My biggest concern for now if how I can fastest was check if a particular bit is set ..

see:-
http://www.arduino.cc/playground/Code/BitMath

Last update I guess (mostly for reference if other people would lookup this thread)

I also changed the code now to parallel output on 8 datapins, and the result is even nicer.

The speed to push out 1 byte of data varies now between 3.25 and 4 microseconds (I save 8 times the clock pulse on a clock pin)

3.25microseconds is needed to setup a 0b00000000 and then it goes upto 4 microseconds for a 0b11111111

So if I calculate at max 4 microseconds, that means that my wanted speed of 250000 bytes / second is achieved.

The only thing I have to still do now is write a little routine which waits for a pin on the controller to change from low to high and then initiate the transfer of 1 byte over this parallel connection.

I have deliberately disabled interrupts during this transfer because if I don't do it, then the controller is going to have a very little delay every 1 milliseconds. I guess thats because arduino by default has some kind of timer running on a millisecond interval.

So, I hope that this interrupt disabling won't make my SD routines useless.

void setup() {
  //set pins to output so you can control the shift register
  
  pinMode(A0, OUTPUT); //bit1
  pinMode(A1, OUTPUT); //bit2
  pinMode(A2, OUTPUT); //bit3
  pinMode(A3, OUTPUT); //bit4
  pinMode(A4, OUTPUT); //bit5
  pinMode(A5, OUTPUT); //bit6
  pinMode(6, OUTPUT);  //bit7
  pinMode(7, OUTPUT);  //bit8
  pinMode(8, OUTPUT);  //latch

  digitalWrite(8, HIGH);
  delay(500);
  digitalWrite(8, LOW);
  delay(500); //just some init code to see easier on logic analyser when the code starts after a reset
  cli();
}

void loop() {
  for (int myValue = 0; myValue < 256; myValue++) {

 PORTB &= ~_BV(0);   // reset latchpin

if (myValue & 0b10000000)  { PORTD |=_BV(7); }//set datapin  
   else { PORTD &= ~_BV(7); }//reset datapin

if (myValue & 0b01000000)  { PORTD |=_BV(6); }//set datapin  
   else { PORTD &= ~_BV(6); }//reset datapin

if (myValue & 0b00100000)  { PORTC |=_BV(5); }//set datapin
   else { PORTC &= ~_BV(5); }//reset datapin

if (myValue & 0b00010000)  { PORTC |=_BV(4); }//set datapin
   else { PORTC &= ~_BV(4); }//reset datapin

if (myValue & 0b00001000)  { PORTC |=_BV(3); }//set datapin
   else { PORTC &= ~_BV(3); }//reset datapin

if (myValue & 0b00000100)  { PORTC |=_BV(2); }//set datapin
   else { PORTC &= ~_BV(2); }//reset datapin

if (myValue & 0b00000010)  { PORTC |=_BV(1); }//set datapin
   else { PORTC &= ~_BV(1); }//reset datapin

if (myValue & 0b00000001)  { PORTC |=_BV(0); }//set datapin
   else { PORTC &= ~_BV(0); }//reset datapin

PORTB |=_BV(0);     // set latchpin
  }
}

educa:
problem is the hardware SPI is allready used by the sd card

The SPI port is not point to point you can connect many things to it you just need to use the chip select pins to indicate who your talking to. Since the arduino does not multitask there is never a time when your reading from the sdcard and writing somewhere else at the exact same moment.