Pages: 1 [2]   Go Down
Author Topic: Fast alternative to digitalRead/digitalWrite  (Read 6697 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 167
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I was very interested in this because I'm writing for dedicated hardware with my LCD data pins contiguous and on the same port.  With a simple benchmark just converting the stock LiquidCrystal library to DigitalPin and nothing else I saw a 32% speed up.  By changing the write4bits method to shift the nibble directly into the port I only saw an additional 1.1% speed increase from the pure DigitalPin version.

Unless I totally mangled my direct port code, which is a very real possibility
Code:
PORTC = (PORTC & (~B00111100)) | ((value << 2) & B00111100);// D0-3 on A2-A5

When I removed the section setting the pins to output in each write the difference between digitalPin and direct port was only .06%

Is that basically what you're getting at or did I miss the point entirely?
Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1477
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You got the point exactly. 

Often what looks great in C/C++ code doesn't optimize well for I/O on AVR chips. 

avr-gcc seems to really understand single bit operations.  Sometimes it does really stupid things with more complex cases.

I am now doing a very general bit-bang SPI implementation for all SPI modes.  I get a factor of four speedup by simple changes that make the compile so what I expect.
Logged

North Queensland, Australia
Online Online
Edison Member
*
Karma: 53
Posts: 1791
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@fat16lib, I have recently converted my older code using FastDigitalIO to your newer DigitalPin library.
The compilation size grew by two bytes, I cannot find the reason why either ( 2 bytes is nothing anyway ).
Also I noticed the 'mode()' function is gone, Was easier to implement in some circumstances.
Logged


0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1477
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I will be posting another version of digitalRead/digitalWrite.  The current version is not working well in a general implementation of software SPI master.  I am also using it for a fast software I2C master. 
Logged

Greenville, IL
Offline Offline
Edison Member
*
Karma: 11
Posts: 1309
Warning Novice on board! 0 to 1 chance of errors!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


  I tested this library on my Uno against using digital.Write and I got a nice improvement in speed. I also thought your library was easy to use once I caught on to terms needed to activate the pins.

 Can this library be used with any Arduino compatible board or do the pins have to be defined in the library first?

 To narrow my question down, I would like to use it on a Leonardo board and "here comes a dream", try to use the library on a Maple.

Great work, thank you for your efforts!
Logged


0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1477
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have defined pins for 168/328, Mega, 644/1284 (Sanguino style), Leonardo, Teensy, and Teensy++.  I haven't tested Leonardo yet.

I am currently doing a lot of development on STM32 and have been thinking about digital I/O for STM32.  STM32 is very different than AVR.  Pins have 15 modes. and there are neat registers to safely set and clear bits in a port.

Here are the modes:
Quote
STM32 pin modes
0 - Analog input.
1 - Push Pull output 10MHz.
2 - Push Pull output 2MHz.
3 - Push Pull output 50MHz.
4 - Digital input.
5 - Open Drain output 10MHz.
6 - Open Drain output 2MHz.
7 - Open Drain output 50MHz.
8 - Digital input with PullUp or PullDown resistor depending on ODR.
9 - Alternate Push Pull output 10MHz.
A - Alternate Push Pull output 2MHz.
B - Alternate Push Pull output 50MHz.
C - Reserved.
D - Alternate Open Drain output 10MHz.
E - Alternate Open Drain output 2MHz.
F - Alternate Open Drain output 50MHz.
Logged

Greenville, IL
Offline Offline
Edison Member
*
Karma: 11
Posts: 1309
Warning Novice on board! 0 to 1 chance of errors!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


  Wow that is a lot of choices! I can see how that would take some time to work out!

Are you posting on a forum related to ARM chips, so that I can follow your work?

Logged


Offline Offline
Full Member
***
Karma: 0
Posts: 167
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If you include both SdFat and DigitalPin in the same program you get a redefinition of 'struct pin_map_t' error
Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1477
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I know the beta has problems like the 'struct pin_map_t' error. 

I am not happy with the beta and have totally restructured this library but have not had time to finish the new library.

The old version did not work well for a number of applications like fast software I2C and SPI.  The new library is very different and won't be backward compatible.
Logged

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 106
Posts: 6374
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
const static pin_map_t pinMap[] = {
  {&DDRD, &PIND, &PORTD, 0},  // D0  0
  {&DDRD, &PIND, &PORTD, 1},  // D1  1
  {&DDRD, &PIND, &PORTD, 2},  // D2  2
  {&DDRD, &PIND, &PORTD, 3},  // D3  3
  {&DDRD, &PIND, &PORTD, 4},  // D4  4
  {&DDRD, &PIND, &PORTD, 5},  // D5  5

The compiler optimizes const static array accesses to constants?  Wow!  That makes the earlier attempts at digitalWriteFast look ... silly.

Hmm.  With a SLIGHT amount of cooperation from the Arduino core team, the pins_arduino.h file(s) could be set up to generate either the existing PROGMEM tables OR const static arrays, so that "fast" versions of things could be written using exactly the same data used for the slow versions:

Code:
const MAYBE_STATIC uint8_t MAYBE_PROGMEM digital_pin_to_port_[] =
{
PB, /* 0 */
PB,
PB,
PB,
PB,
//etc

// with:
#define MAYBE_STATIC static
#define MAYBE_PROGMEM
#include <pins_arduino.h>
Or...
Code:
#define digital_pin_to_port_M \
{ \
PB, /* 0 */ \
PB,\
PB,\
PB,\
PB,\
//etc \
}

const uint8_t PROGMEM digital_pin_to_port_PGM[] = digital_pin_to_port_M;
static const uint8_t digital_pin_to_port_S[] = digital_pin_to_port_M;
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 47
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is extremely interesting, any improvements?
Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1477
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I can't improve the speed since functions like pin.high() and pin.low() compile to a single sbi or cbi instruction for low address I/O ports.  All ports on the 328 and ports A-G on the Mega are low address.  These instructions execute in 2 cycles or 125 ns on a 16 MHz cpu.

I have added software SPI which runs at about 2 MHz.  This library supports all SPI modes for MSB first.  It would be easy to add an option for LSB first.

I have not posted the latest version as a standalone library.  The latest version of DigitalPin with SoftSPI is used in the new 20120719 version of SdFat.  The files DigitalPin.h and SoftSPI.h are in the SdFat/utility folder and SdFat is here http://code.google.com/p/sdfatlib/downloads/list.

I have also written a software I2C library based on the DigitalPin library that runs at 400 kHz.  I plan to post this I2C library soon.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 47
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I can't improve the speed since functions like pin.high() and pin.low() compile to a single sbi or cbi instruction for low address I/O ports.  All ports on the 328 and ports A-G on the Mega are low address.  These instructions execute in 2 cycles or 125 ns on a 16 MHz cpu....

Btw this is a great result! fastDigitalWrite it's still one of the most used library because the original digitalWrite it's silly slow for many applications but the development it's stuck at 2010 and not provide any support for new micros and with the new pin management of arduino I dubt it will be useful as in the past.
Man, you made a great work! I know that direct port manipulation it's easier but the beauty of change processor and reuse the libraries for experiments without spend hours around PORTwhatever it's a dream!
I will check how you used in your sdfatlib, I'm planning to apply to liquidCrystal lib (I hope will not a nightmare...) and was really great you added any unsupported processor.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh. You had same problem as I do. Arduino is slow... Well I had another problem. I can't create easy libraries with bare avr c. So I started project to overcome this problem.

As a result I have very nice implementation for digital pins. That is only thing really working yet. Timers and analogRead is next.

Wanted to let you know what I have found out, so here is the project: https://github.com/raphendyr/yaal
Logged

North Queensland, Australia
Online Online
Edison Member
*
Karma: 53
Posts: 1791
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Oh. You had same problem as I do. Arduino is slow... Well I had another problem. I can't create easy libraries with bare avr c. So I started project to overcome this problem.

As a result I have very nice implementation for digital pins. That is only thing really working yet. Timers and analogRead is next.

Wanted to let you know what I have found out, so here is the project: https://github.com/raphendyr/yaal

Hi, had a look at your library. Seems you are doing similar things to the ideas I'm implementing in my own library. I also noticed you are using a very basic version of my AtomicBlock library. I'm about to release a new version compatible with AVR, AVR32, PIC32, ARM Cortex M/R  if you are interested.
« Last Edit: November 01, 2012, 06:07:25 am by pYro_65 » Logged


Pages: 1 [2]   Go Up
Jump to: