Commits

F Malpartida  committed 46e2752

closes #13 - rename private variable for LCD bit-mask pin.
closes #15 - comments added to header files and method descriptions.
closes #16 - added critical sections to fastIOs and associated usage on the LiquidCrystal_SR class.
ref #14 - partially closed pending review.

  • Participants
  • Parent commits 0d38b92

Comments (0)

Files changed (9)

 // (https://github.com/chipKIT32/chipKIT32-MAX/blob/master/hardware/pic32/
 //   cores/pic32/wiring_digital.c)
 // ---------------------------------------------------------------------------
-
+#include <util/atomic.h> // for critical section management
 #include "FastIO.h"
 
 fio_register fio_pinToOutputRegister(uint8_t pin, uint8_t initial_state)
 #ifdef FIO_FALLBACK
 	digitalWrite(pinBit, value);
 #else
-	if(value == LOW)
+   ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
-		fio_digitalWrite_LOW(pinRegister,pinBit);
-	}
-   else
-   {
-		fio_digitalWrite_HIGH(pinRegister,pinBit);
-	}
+      if(value == LOW)
+      {
+         fio_digitalWrite_LOW(pinRegister,pinBit);
+      }
+      else
+      {
+         fio_digitalWrite_HIGH(pinRegister,pinBit);
+      }
+   }
 #endif
 }
 
 #endif
 }
 
-void fio_shiftOut ( fio_register dataRegister, fio_bit dataBit, fio_register clockRegister, 
-                    fio_bit clockBit, uint8_t value, uint8_t bitOrder)
+void fio_shiftOut ( fio_register dataRegister, fio_bit dataBit, 
+                    fio_register clockRegister, fio_bit clockBit, 
+                    uint8_t value, uint8_t bitOrder)
 {
 	// # disable interrupts
-	// uint8_t oldSREG = SREG;
-	// cli();
 	int8_t i;
 
-	for(i = 0; i < 8; i++)
+   ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
-		if (bitOrder == LSBFIRST)
+      for(i = 0; i < 8; i++)
       {
-			fio_digitalWrite(dataRegister, dataBit, !!(value & (1 << i)));
-		}
-      else
-      {
-			fio_digitalWrite(dataRegister, dataBit, !!(value & (1 << (7 - i))));
-		}
-		fio_digitalWrite_HIGH (clockRegister, clockBit);
-		// Switching is a little bit faster
-		fio_digitalWrite_SWITCH (clockRegister,clockBit);
-	}
-	// # enable interrupts
-	// SREG = oldSREG;
+         if (bitOrder == LSBFIRST)
+         {
+            fio_digitalWrite(dataRegister, dataBit, !!(value & (1 << i)));
+         }
+         else
+         {
+            fio_digitalWrite(dataRegister, dataBit, !!(value & (1 << (7 - i))));
+         }
+         fio_digitalWrite_HIGH (clockRegister, clockBit);
+         
+         // Switching is a little bit faster
+         fio_digitalWrite_SWITCH (clockRegister,clockBit);
+      }
+   } // end critical section
 }
 
-void fio_shiftOut(fio_register dataRegister, uint8_t dataBit, fio_register clockRegister, uint8_t clockBit)
+void fio_shiftOut(fio_register dataRegister, uint8_t dataBit, 
+                  fio_register clockRegister, uint8_t clockBit)
 {
-	// shift out 0x0 (B00000000) fast, byte order is irrelevant
-	fio_digitalWrite_LOW (dataRegister, dataBit);
+   ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+   {
+      // shift out 0x0 (B00000000) fast, byte order is irrelevant
+      fio_digitalWrite_LOW (dataRegister, dataBit);
 
-	for(uint8_t i = 0; i<8; ++i)
-   {
-		fio_digitalWrite_HIGH (clockRegister, clockBit);
-		fio_digitalWrite_SWITCH (clockRegister, clockBit);
-	}
+      for(uint8_t i = 0; i<8; ++i)
+      {
+         fio_digitalWrite_HIGH (clockRegister, clockBit);
+         fio_digitalWrite_SWITCH (clockRegister, clockBit);
+      }
+   }
 }
 void fio_shiftOut1_init(uint8_t pin)
 {
 	fio_digitalWrite(shift1Register,shift1Bit,HIGH);
 	delayMicroseconds(300);
 }
-void fio_shiftOut1(fio_register shift1Register, fio_bit shift1Bit, uint8_t value, boolean noLatch)
+void fio_shiftOut1(fio_register shift1Register, fio_bit shift1Bit, uint8_t value, 
+                   boolean noLatch)
 {
 	/*
-	 * this function are based on Shif1 protocol developed by Roman Black (http://www.romanblack.com/shift1.htm)
+	 * this function are based on Shif1 protocol developed by Roman Black 
+    *    (http://www.romanblack.com/shift1.htm)
 	 *
 	 * test sketches:
 	 * 	http://pastebin.com/raw.php?i=2hnC9v2Z
     *                   arduino-one-wire-shift-register-prototype)
 	 * 	7HC595N
 	 */
-	// disable interrupts since timing is going to be critical
-	uint8_t oldSREG;
-	oldSREG = SREG;
-	cli();
 
 	// iterate but ignore last bit (is it correct now?)
 	for(int8_t i = 7; i>=0; --i)
    {
 
-		// assume that pin is HIGH (smokin' pot all day... :) - requires initialization
-		if(LOW==!!(value & (1 << i)))
+		// assume that pin is HIGH (smokin' pot all day... :) - requires 
+      // initialization
+		if(value & _BV(i))
       {
-			// LOW = 0 Bit
-			fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,LOW);
-			// hold pin LOW for 15us
-			delayMicroseconds(15);
-			fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,HIGH);
-			// hold pin HIGH for 30us
-			delayMicroseconds(30);
+         ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+         {
+            // HIGH = 1 Bit
+            fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,LOW);
+            //hold pin LOW for 1us - done! :)
+            fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,HIGH);
+            //hold pin HIGH for 15us
+         } // end critical section
+         delayMicroseconds(15);
 		}
       else
       {
-			// HIGH = 1 Bit
-			fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,LOW);
-			//hold pin LOW for 1us - done! :)
-			fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,HIGH);
-			//hold pin HIGH for 15us
-			delayMicroseconds(15);
+         ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+         {
+            // LOW = 0 Bit
+            fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,LOW);
+            // hold pin LOW for 15us
+            delayMicroseconds(15);
+            fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,HIGH);
+         } // end critical section
+         // hold pin HIGH for 30us
+         delayMicroseconds(30);         
 		}
 		if(!noLatch && i==1)
       {
    
 	if(!noLatch)
    {
-		// send last bit (=LOW) and Latch command
-		fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,LOW);
-		// Hold pin low for 200us
-		delayMicroseconds(199);
-		fio_digitalWrite_HIGH(shift1Register,shift1Bit);
-		// Hold pin high for 300us and leave it that way - using explicit HIGH here, just in case.
-		delayMicroseconds(299);
+      ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+      {
+         // send last bit (=LOW) and Latch command
+         fio_digitalWrite_SWITCHTO(shift1Register,shift1Bit,LOW);
+      } // end critical section
+      delayMicroseconds(199); 		// Hold pin low for 200us
+
+      ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+      {
+         fio_digitalWrite_HIGH(shift1Register,shift1Bit);
+      } // end critical section
+		delayMicroseconds(299);   // Hold pin high for 300us and leave it that 
+                                // way - using explicit HIGH here, just in case.
 	}
+}
 
-	// enable interrupts
-	SREG = oldSREG;
-
-}
 void fio_shiftOut1(uint8_t pin, uint8_t value, boolean noLatch)
 {
 	fio_shiftOut1(fio_pinToOutputRegister(pin, SKIP),fio_pinToBit(pin),value, noLatch);
 #include <inttypes.h>
 #include <util/delay.h>
 
+
 /*!
  @defined 
  @abstract   Enables IO digitalRead/digitalWrite fall back for non-AVR
  */
 #ifndef __AVR__
 #define FIO_FALLBACK
+#define ATOMIC_BLOCK
+#define ATOMIC_RESTORESTATE
 #endif
 
 // PUBLIC CONSTANTS DEFINITIONS
 
 
 #ifndef FIO_FALLBACK
-typedef volatile uint8_t * fio_register;
+typedef volatile uint8_t *fio_register;
 #else
 // remove volatile to give optimizer a chance
 typedef uint8_t fio_register;
    // before sending commands. Arduino can turn on way before 4.5V so we'll wait 
    // 50
    // ---------------------------------------------------------------------------
-   delayMicroseconds(100000); 
+   delay (100); // 100ms delay
       
    //put the LCD into 4 bit or 8 bit mode
    // -------------------------------------
    }
 }
 
+void LCD::backlight ( void )
+{
+   setBacklight(255);
+}
+
+void LCD::noBacklight ( void )
+{
+   setBacklight(0);
+}
+
 // General LCD commands - generic methods used by the rest of the commands
 // ---------------------------------------------------------------------------
 void LCD::command(uint8_t value) 
 // it has been extended to drive 4 and 8 bit mode control, LCDs and I2C extension
 // backpacks such as the I2CLCDextraIO using the PCF8574* I2C IO Expander ASIC.
 //
+// The functionality provided by this class and its base class is identical
+// to the original functionality of the Arduino LiquidCrystal library.
+//
 // @version API 1.1.0
 //
 //
     initializes the LCD, therefore, it MUST be called prior to using any other
     method from this class.
     
-    This method is pure abstract, it is dependent on each derived class from
-    this base class to implement the internals of how the LCD is initialized
-    and configured.
+    This method is abstract, a base implementation is available common to all LCD
+    drivers. Should it not be compatible with some other LCD driver, a derived
+    implementation should be done on the driver specif class.
     
     @param      cols[in] the number of columns that the display has
     @param      rows[in] the number of rows that the display has
    // --------------------------------------------------------------------------
    /*!
     @function
-    @abstract   Switch-on/off the LCD backlight.
-    @discussion Switch-on/off the LCD backlight.
-    The setBacklightPin has to be called before setting the backlight for
-    this method to work. @see setBacklightPin. This method is device dependent
-    and can be programmed on each subclass. An empty function call is provided
-    that does nothing.
-    
-    @param      mode: backlight mode (HIGH|LOW)
-    */
-   virtual void setBacklight ( uint8_t mode ) { };
-   
-   /*!
-    @function
     @abstract   Sets the pin to control the backlight.
     @discussion Sets the pin in the device to control the backlight.
     This method is device dependent and can be programmed on each subclass. An 
     
     @param      mode: backlight mode (HIGH|LOW)
     */
-   virtual void setBacklightPin ( uint8_t pin ) { };
+   virtual void setBacklightPin ( uint8_t value ) { };
+   
+   /*!
+    @function
+    @abstract   Sets the pin to control the backlight.
+    @discussion Sets the pin in the device to control the backlight. The behaviour
+    of this method is very dependent on the device. Some controllers support
+    dimming some don't. Please read the actual header file for each individual
+    device. The setBacklightPin method has to be called before setting the backlight.
+    @see setBacklightPin.
+    
+    NOTE: The prefered methods to control the backlight are "backlight" and
+    "noBacklight".
+    
+    @param      0..255 - the value is very dependent on the LCD, however, 0
+    will be interpreted as off.
+    */
+   virtual void setBacklight ( uint8_t value ) { };
+   
+   /*!
+    @function
+    @abstract   Switch-on the LCD backlight.
+    @discussion Switch-on the LCD backlight.
+    The setBacklightPin has to be called before setting the backlight for
+    this method to work. @see setBacklightPin. 
+   */
+   void backlight ( void );
+
+   /*!
+    @function
+    @abstract   Switch-off the LCD backlight.
+    @discussion Switch-off the LCD backlight.
+    The setBacklightPin has to be called before setting the backlight for
+    this method to work. @see setBacklightPin. 
+    */   
+   void noBacklight ( void );
    
    /*!
     @function

File LiquidCrystal.cpp

 }
 
 //
-// setBackligh
-void LiquidCrystal::setBacklight ( uint8_t mode )
-{
-   if ( _backlightPin != LCD_NOBACKLIGHT )
-   {
-      digitalWrite ( _backlightPin, mode );
-   }
-}
-
-//
 // setBacklightPin
 void LiquidCrystal::setBacklightPin ( uint8_t pin )
 {
    _backlightPin = pin;
 }
 
+//
+// setBackligh
+void LiquidCrystal::setBacklight ( uint8_t value )
+{
+   if ( _backlightPin != LCD_NOBACKLIGHT )
+   {
+      analogWrite ( _backlightPin, value );
+   }
+}
+
 // PRIVATE METHODS
 // ---------------------------------------------------------------------------
 

File LiquidCrystal.h

 // on the Hitachi HD44780 and compatible chipsets using the parallel port of
 // the LCD (4 bit and 8 bit).
 //
-// The functionality provided by this class and its base class is identical
-// to the original functionality of the Arduino LiquidCrystal library.
 //
 //
 // @author F. Malpartida - fmalpartida@gmail.com
    
    /*!
     @function
+    @abstract   Sets the pin to control the backlight.
+    @discussion Sets the pin in the device to control the backlight.
+    
+    @param      pin: pin assigned to the backlight
+    */
+   void setBacklightPin ( uint8_t pin );
+      
+   /*!
+    @function
     @abstract   Switch-on/off the LCD backlight.
     @discussion Switch-on/off the LCD backlight.
     The setBacklightPin has to be called before setting the backlight for
-    this method to work. @see setBacklightPin.
+    this method to work. @see setBacklightPin. For dimming control of the
+    backlight, the configuration pin must be a PWM output pin. Dim control
+    is achieved by passing a value from 1 to 255 as a parameter. If the
+    pin configured when calling the setBacklightPin does not support PWM,
+    then: (0..127) backlight off, (128..255) backlight on.
     
-    @param      mode: backlight mode (HIGH|LOW)
+    @param      value: backlight value. 0: off, 1..255: dim control of the 
+    backlight. For negative logic 255: off, 254..0: dim control.
+    For non PWM pins: 0..127 - backligh off, 128..255 - backlight on.
     */
-   void setBacklight ( uint8_t mode );
-   
-   /*!
-    @function
-    @abstract   Sets the pin to control the backlight.
-    @discussion Sets the pin in the device to control the backlight.
-    
-    @param      mode: backlight mode (HIGH|LOW)
-    */
-   void setBacklightPin ( uint8_t pin );
-   
+   void setBacklight ( uint8_t value );
    
 private:
    

File LiquidCrystal_I2C.cpp

 {
    _Addr = lcd_Addr;
    
-   _backlightPin  = 0x0;
-   _backlightMask = LCD_NOBACKLIGHT;
+   _backlightPinMask = 0x0;
+   _backlightStsMask = LCD_NOBACKLIGHT;
    
    _En = EN;
    _Rw = RW;
 {
    _Addr = lcd_Addr;
    
-   _backlightPin  = 0;
-   _backlightMask = LCD_NOBACKLIGHT;
+   _backlightPinMask = 0;
+   _backlightStsMask = LCD_NOBACKLIGHT;
    
    _En = ( 1 << En );
    _Rw = ( 1 << Rw );
 {
    _Addr = lcd_Addr;
    
-   _backlightPin  = 0;
-   _backlightMask = LCD_NOBACKLIGHT;
+   _backlightPinMask = 0;
+   _backlightStsMask = LCD_NOBACKLIGHT;
 
    _En = ( 1 << En );
    _Rw = ( 1 << Rw );
 
 // User commands - users can expand this section
 //----------------------------------------------------------------------------
-
 // Turn the (optional) backlight off/on
-//
-// setBacklight
-void LiquidCrystal_I2C::setBacklight( uint8_t mode ) 
-{
-   if ( mode == HIGH )
-   {
-      _backlightMask = _backlightPin & LCD_BACKLIGHT;
-      
-   }
-   else 
-   {
-      _backlightMask = _backlightPin & LCD_NOBACKLIGHT;
-   }
-   _i2cio.write( _backlightMask );
-}
 
 //
 // setBacklightPin
 void LiquidCrystal_I2C::setBacklightPin ( uint8_t pin )
 {
-   _backlightPin = ( 1 << pin );
+   _backlightPinMask = ( 1 << pin );
 }
 
+//
+// setBacklight
+void LiquidCrystal_I2C::setBacklight( uint8_t value ) 
+{
+   if ( value > 0 )
+   {
+      _backlightStsMask = _backlightPinMask & LCD_BACKLIGHT;
+      
+   }
+   else 
+   {
+      _backlightStsMask = _backlightPinMask & LCD_NOBACKLIGHT;
+   }
+   _i2cio.write( _backlightStsMask );
+}
+
+
 // PRIVATE METHODS
 // ---------------------------------------------------------------------------
 
       mode = _Rs;
    }
    
-   pinMapValue |= mode | _backlightMask;
+   pinMapValue |= mode | _backlightStsMask;
    _i2cio.write ( pinMapValue );
    pulseEnable ( pinMapValue );
 }

File LiquidCrystal_I2C.h

    
    /*!
     @function
+    @abstract   Sets the pin to control the backlight.
+    @discussion Sets the pin in the device to control the backlight. This device
+    doesn't support dimming backlight capability.
+    
+    @param      0: backlight off, 1..255: backlight on.
+    */
+   void setBacklightPin ( uint8_t value );
+   
+   /*!
+    @function
     @abstract   Switch-on/off the LCD backlight.
     @discussion Switch-on/off the LCD backlight.
     The setBacklightPin has to be called before setting the backlight for
     */
    void setBacklight ( uint8_t mode );
    
-   /*!
-    @function
-    @abstract   Sets the pin to control the backlight.
-    @discussion Sets the pin in the device to control the backlight.
-    
-    @param      mode: backlight mode (HIGH|LOW)
-    */
-   void setBacklightPin ( uint8_t pin );
-   
-   
 private:
    
    /*!
    
    
    uint8_t _Addr;             // I2C Address of the IO expander
-   uint8_t _backlightPin;     // Backlight IO pin
-   uint8_t _backlightMask;    // Backlight status mask
+   uint8_t _backlightPinMask; // Backlight IO pin mask
+   uint8_t _backlightStsMask; // Backlight status mask
    I2CIO   _i2cio;            // I2CIO PCF8574* expansion module driver I2CLCDextraIO
    uint8_t _En;               // LCD expander word for enable pin
    uint8_t _Rw;               // LCD expander word for R/W pin

File LiquidCrystal_SR.cpp

 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
+#include <util/atomic.h> // for critical section management
 
 #if (ARDUINO <  100)
 #include <WProgram.h>
 // CONSTRUCTORS
 // ---------------------------------------------------------------------------
 // Assuming 1 line 8 pixel high font
-LiquidCrystal_SR::LiquidCrystal_SR ( uint8_t srdata, uint8_t srclock, 
-                                     uint8_t enable ) 
+LiquidCrystal_SR::LiquidCrystal_SR (uint8_t srdata, uint8_t srclock, 
+                                    uint8_t enable ) 
 {
 	init ( srdata, srclock, enable, 1, 0 );
 }
 
 //
 // init
-void LiquidCrystal_SR::init(uint8_t srdata, uint8_t srclock, uint8_t enable, uint8_t lines, uint8_t font)
+void LiquidCrystal_SR::init(uint8_t srdata, uint8_t srclock, uint8_t enable, 
+                            uint8_t lines, uint8_t font)
 {
    // Initialise private variables
    _two_wire = 0;
-
+   
    _srDataRegister = fio_pinToOutputRegister(srdata);
    _srDataBit = fio_pinToBit(srdata);
    _srClockRegister = fio_pinToOutputRegister(srclock);
    _srClockBit = fio_pinToBit(srclock);
-
+   
    if (enable == TWO_WIRE)
    {
       _two_wire = 1;
       _srEnableRegister = fio_pinToOutputRegister(enable);
       _srEnableBit = fio_pinToBit(enable);
    }
-
+   
    // Configure control pins as outputs
    // ------------------------------------------------------------------------
-
+   
    _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x10DOTS;
 }
 
+//
 // shiftIt
 void LiquidCrystal_SR::shiftIt(uint8_t val)
 {
       fio_shiftOut(_srDataRegister, _srDataBit, _srClockRegister, _srClockBit);
    }
    fio_shiftOut(_srDataRegister, _srDataBit, _srClockRegister, _srClockBit, val, MSBFIRST);
-
+   
    // LCD ENABLE PULSE
    //
    // While this library is written with a shift register without an output
    // latch. The shiftregister latch pin (STR, RCL or similar) is then
    // connected to the LCD enable pin. The LCD is (very likely) slower
    // to read the Enable pulse, and then reads the new contents of the SR.
-   fio_digitalWrite_HIGH(_srEnableRegister, _srEnableBit);
-   waitUsec (1);         // enable pulse must be >450ns               
-   fio_digitalWrite_SWITCHTO(_srEnableRegister, _srEnableBit, LOW);
+   ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
+   {
+      fio_digitalWrite_HIGH(_srEnableRegister, _srEnableBit);
+      waitUsec (1);         // enable pulse must be >450ns               
+      fio_digitalWrite_SWITCHTO(_srEnableRegister, _srEnableBit, LOW);
+   } // end critical section
    waitUsec ( 37 );      // commands need > 37us to settle
 }
 
 
 
 /************ low level data pushing commands **********/
-
+//
 // send
 void LiquidCrystal_SR::send(uint8_t value, uint8_t mode)
 {
 }
 
 //
+// setBacklightPin
+void LiquidCrystal_SR::setBacklightPin ( uint8_t pin )
+{ }
+
+//
 // setBacklight
 void LiquidCrystal_SR::setBacklight ( uint8_t mode ) 
 { }
 
-
-void LiquidCrystal_SR::setBacklightPin ( uint8_t pin )
-{ }