Faster Shiftout, how?

Im driving a thermal printer head from the arduino uno, it takes 384 bits per line, so i have to Shfitout 384 bits each time.

Currently Im using a For loop:

void Write() {
  digitalWrite(latchPin, HIGH);
  for (int i = 1; i <= 48; i++) {
    shiftOut(dataPin, clockPin, MSBFIRST, B11111111); 
  }
  digitalWrite(latchPin, LOW);
}

However the problem with this code, that i suspect is that it isnt fast enough (?). I can write 24 bytes but nothing gets transmitted after that.

PS i have little or no understanding of specific timing diagrams. However, i just tried the normal shiftout with my application and it seemed to work, albeit for just 24 bytes instead of the full 48 bytes. If anyone wants ill attach the timing diagrams/datasheet.

I can't see how the speed has any bearing on how many bytes are transmitted. It may have a bearing on how the printer handles them.

I can write 24 bytes but nothing gets transmitted after that.

How do you know this? Logic analyser trace?

If anyone wants ill attach the timing diagrams/datasheet.

That would be good.


Rob

You can write your own shiftout function and remove the for loop.
Have a look on wiring_shift.c file

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
	uint8_t i;
	for (i = 0; i < 8; i++)  {
		if (bitOrder == LSBFIRST)
			digitalWrite(dataPin, !!(val & (1 << i)));
		else	
			digitalWrite(dataPin, !!(val & (1 << (7 - i))));			
		digitalWrite(clockPin, HIGH);
		digitalWrite(clockPin, LOW);		
	}
}

change

uint8_t i;
	for (i = 0; i < 8; i++)

by

uint16_t i;                        // with  uint8_t  imax= 255  too  low for 384 bits
	for (i = 0; i < 383; i++)   // i<8 is for transmiting byte   --> i<383 is for transmiting 384 bits

Other improvement: remove the arduino function digitalWrite and use direct register DDRx and PORTx manipulation. You will be 10 time faster.
Other solution use SPI : it can works with a 8MHz clock.

Graynomad:
I can't see how the speed has any bearing on how many bytes are transmitted. It may have a bearing on how the printer handles them.

I can write 24 bytes but nothing gets transmitted after that.

How do you know this? Logic analyser trace?

If anyone wants ill attach the timing diagrams/datasheet.

That would be good.


Rob

I do agree it is quite odd, the transmission cut off. Whats even more odd is that the thermal printer print array consists of 6 heating blocks, each of 8 bytes. I can transmit perfectly to the first 3 but not the last three. Seldom i manage to address the last 3 but it is not consistent so im thinking its a speed issue.

No it i dont have a logic analyzer, its just a guess.

I have attached the datasheet.

68tjs:
You can write your own shiftout function and remove the for loop.
Have a look on wiring_shift.c file

void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)

{
uint8_t i;
for (i = 0; i < 8; i++)  {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}



change 


uint8_t i;
for (i = 0; i < 8; i++)



by


uint16_t i;                        // with  uint8_t  imax= 255  too  low for 384 bits
for (i = 0; i < 383; i++)  // i<8 is for transmiting byte  --> i<383 is for transmiting 384 bits




Other improvement: remove the arduino function digitalWrite and use direct register DDRx and PORTx manipulation. You will be 10 time faster.
Other solution use SPI : it can works with a 8MHz clock.

Would not using a for loop also speed it up? Im taking up your advise on using direct port addressing for sure!

LTPZ245-B_J.pdf (1.24 MB)

SPI, best way. 384 bits = 48 bytes, send the data from an array:

digitalWrite (ssPin, LOW);
SPI.transfer(lineArray[lineNumber+0]);
SPI.transfer(lineArray[lineNumber+1]);
:
:
SPI.transfer(lineArray[lineNumber+46]);
SPI.transfer(lineArray[lineNumber+47]);
digitalWrite (ssPin, LOW);
lineNumber = lineNumber + 48;
if (lineNumber == endofLines){lineNumber = 0;} // ready for next page?

If you use a 1284P processer, can have 300 lines in its 16K SRAM and still have nearly 2K SRAM free for the code.
I offer 1284P boards in several form factors, here is one of them:
http://www.crossroadsfencing.com/BobuinoRev17/

uint16_t i; // with uint8_t imax= 255 too low for 384 bits
for (i = 0; i < 383; i++) // i<8 is for transmiting byte --> i<383 is for transmiting 384 bits

What? Did I miss something?

val is a byte, 8 bits, and you want to shift through it 384 bits(48 bytes)?

You can probably save a few cycles if you rewrite the digitalWrite function, and take out the IF statements.

The shiftout function is written correctly, granted some overhead can be taken out, but for the most part it is correct. However the SPI library, could be a better choice to use in this case.

Edit: CrossRoads beat me to it.

SPI is much better.
Set SPI speed divisor to 2, hardcode the SPI transfer line, can send a byte every 17 clocks, just over 1uS/byte. Replace lines above with
spdr = lineArray[lineNumber+0];nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;

Need to add an assembler #include line at the top of the sketch, I don't recall what it is offhand. But this way is the fastest thing going. Can turn off interrupts while the transfers are in process to prevent micros() and millis() interrupts.

SPI is fastest.

for non SPI solution check - FastShiftOut with Print interface (experimental) - Libraries - Arduino Forum -

I suspect that your problem is not that the arduino is to slow but that it is FAR TO FAST. compared to a thermal printer the arduino is lightning fast. I think you are over running the printers buffer. Try a delay(100) every 3 bytes to start with. if that works paly around with the value of the delay()

Mark