Arduino is Slow - and how to fix it! by RazorConcepts
1.bmp
Arduino is slow? What? This instructable will show just how slow a part of Arduino is, and how to fix it.
 
It’s true – more specifically, Arduino’s digitalWrite command takes a considerable amount of time. If you are just switching on a LED once or something, you won’t be able to notice it. However, I realized how slow it was while I was trying to use a TLC5947 PWM driver. That requires the microcontroller to shift in 288 bytes each time! Each byte required about 12 digitalWrites, for a total of 3456 digitalWrites each time I wanted to shift in new data to the TLC5947.
 
How long did that take? 30 seconds of just digitalWrite!
 
But there is a solution – using “true c” style commands, or what the AVR GCC (GNU C Compiler) uses. The brains behind Arduinos are ATMega168s or ATMega328s. The AVR community typically uses “true c” commands to program these chips, using AVR Studio 4. The advantage of using these “true c” commands is that it does exactly what you tell it to do.
 
But before we get in to these commands, we must get familiar with port and pin definitions in the next step!

(If you predict you will like this instructable, feel free to vote for the Arduino contest!)
 
Remove these adsRemove these ads by Signing Up

Step 1: The Truth about Pins

pins.png
Arduino users know that the pins are labeled as digital 0-13 and analog 0-5. The makers behind Arduino used this for simplicity. The actual ATMega chip’s pins are labeled differently, however. Each pin has an assigned letter and number. The numbers range from 0-7. For example, pins can be A0-A8, B0-B8, and so on. All of the AVR 8-bit pins are labeled this way.
 
To help you clarify which digital/analog pin corresponds to which AVR pin, see the chart below.
 
My Seeeduino has a LED built in on digial pin 13. So, looking at the chart, its real pin would be B5.
 
Next I will show you what the actual C command is.
jackocurly0074 says: Jan 31, 2013. 3:06 AM
If you count down rather than up in the loop it will be even faster! On my Arduino Mega changing the loop to count down for the True C commands reduced the time taken from 288microseconds to 192 microseconds, big difference if you need it to be as fast as possible!
rcarvalho4 says: Nov 13, 2011. 6:57 AM
It's better change just the part after the logic operator:

PORTB |= 0b00100000;
PORTB &= ~0b00000000;

If you don't use the logic operators, but just the equal "=" sign, all the pins are going to be set like the byte you sent, not just pin B5. In the case where you set B5 high, you would set all ohter B pins to low.
n8hfi says: Apr 8, 2010. 9:45 AM
Part of the reason this works is that the DigitalWrite() and DigitalRead() do some error checking before it sets the register bit--in particular, it checks and turns off PWM if it's enabled for that pin.  Directly accessing the bit yourself is fine, but you're also assuming responsibility for skipping the check.

This is pretty safe if your sketch is simple and doesn't do much multitasking or multiplexing of pins, but can get perilous if you've got a complex one.
vilts says: Mar 21, 2010. 2:31 PM
 I wonder why I get this error:

In function void loop():
Error: 'PB5' was not declared in this scope.

I use 0018 software.


I used form PORTB = B.....;

and it took 3808 vs 284 microseconds.

I'm trying to get TLC5945 communicating with arduino, no luck with digitalWrites, hopefully this version works.
eewithmac says: Apr 7, 2010. 12:47 AM
 I have the same problem. The example code is obviously missing something. Where and how should PB5 be declared? 

Me, I'm trying to PWM on all the pins of an Arduino Duemilanove to dim some LEDs. 
RazorConcepts (author) says: Apr 7, 2010. 2:24 AM
 Hmm, compiles fine for me on 0015, it may be something with the new software.

If anyone has problems, replace
" PORTB |= _BV(PB5);
  PORTB &= ~_BV(PB5);"

with:
"PORTB = 0b00100000;
PORTB = 0b00000000;"

Which should toggle PB5 like the original code. PB5 shouldnt have to be declared, as winAVR should recognize it as a pin, but arduino 0018 may be doing something funky with that.
just_watching says: Jan 18, 2010. 10:15 AM
Thanks this helped a lot becaus its the only way to programm the 16 extra pins on the Seeduino Mega
zuixro says: Dec 9, 2009. 3:19 PM
Thanks for this instructable. Not only does this save a lot of time, it also knocks the program size down quite a bit.  You can also you the registers DDRx an PINx (where x is the letter of the port) to change a port's input/output status, and to check what the input value is.
ghaon says: Nov 20, 2009. 10:06 AM
 So do you then use the AVR Studio 4? 
Or how do you program an Arduino in this way?
Can you use the Arudino's usb ftdi connection?

Please elaborate. Thanks!
RazorConcepts (author) says: Nov 20, 2009. 11:16 AM
I use Arduino with the "true c" style commands.

You can use AVR Studio 4, however it is quite complicated and you cannot use the usb connection, you will need a ISP programmer to burn the programs.
funlw65 says: Nov 12, 2009. 7:20 AM
Maybe using this "Arduino" ?


wholder says: Oct 26, 2009. 11:01 AM
Actually, there is a very nice writeup on "Direct Port Manipulation" (which is the Arduino folk's name for what you are doing) on the Arduino site.  Here's the link:

  http://www.arduino.cc/en/Reference/PortManipulation

The description at the top of the page says "Port registers allow for lower-level and faster manipulation of the i/o pins of the microcontroller on an Arduino board."

Wayne
WyoJustin says: Oct 25, 2009. 11:17 AM
Nice tutorial.  You should enter it into the Arduino contest.
gmoon says: Oct 25, 2009. 5:10 AM
Some explanation of C "bitwise" operators might be helpful, too... And maybe break it down without using compound assignment ops first.

Here's my fav bitwise link: AVR bit tutorial

Other than that, it's a good 'ible...
RazorConcepts (author) says: Oct 25, 2009. 9:20 AM
Thanks! That may be a bit complicated, but I added a final step with that link. 
RazorConcepts (author) says: Oct 25, 2009. 9:21 AM
*facepalm*
horrible pun was unintended
Nerdz says: Oct 24, 2009. 11:02 PM
How come you didnt you Hardware SPI instead of Bit Banging the commands to the PWM chip? I checked briefly and it seems it use SPI commands. Looking at the Atmega168 Data sheet, It Does have support for hardware SPI, and if you used hardware, it would much Much faster than bit Banging SPI Commands since you can usually get up to 20Mhz Data Transfer depending on your internal clock (or external, but usually it requires you to go with the max clock rate for the chip) since it would Free up the CPU to do other things.
richms says: Oct 25, 2009. 5:16 AM
SPI uses the USART doesnt it? And thats pre-wired on the arduino to support the bootloader
RazorConcepts (author) says: Oct 25, 2009. 9:01 AM
True, actually there is a TLC5940 library for Arduino that uses SPI, however I wanted to see what was actually going on so I just did it the "manual" way by bit banging.

SPI doesn't use the USART, it uses SS/MOSI/MISO/SCK, the latter 3 are used for ISP programming also. 
Dantex says: Oct 25, 2009. 6:56 AM
does this work for arduino mega? (chip is atmega1280
RazorConcepts (author) says: Oct 25, 2009. 8:58 AM
 Yes it does, however I cannot find a chart that shows which arduino pin goes to which pin... you may have to take a peek in to the schematic of the Arduino Mega.
mtbf0 says: Oct 25, 2009. 6:18 AM
reading and writing pwm pins will also be somewhat slower than writing non-pwm pins.

hmmm, i notice that there's no longer any range checking on pin numbers.  although this speeds things up i wonder what havoc a pinMode or digitalWrite to some out of range value might wreak.
flof says: Oct 25, 2009. 5:36 AM
Good to know that there is such an overhead!
How does the ShiftOut() command compare to this? Looking at the arduino reference it seems to be dedicated for this task (if the SPI pins are available..)
Would be nice if someone posts some numbers, since i do not own an arduino to test with..

westfw says: Oct 25, 2009. 1:27 AM
There's a pretty extensive discussion on pin-toggling on the arduino forums here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230286016

Pro

Get More Out of Instructables

Already have an Account?

close

PDF Downloads
As a Pro member, you will gain access to download any Instructable in the PDF format. You also have the ability to customize your PDF download.

Upgrade to Pro today!