Fix to have load pin working with SPI1.

Dependencies:   mbed

Fork of Max7221 by Dwayne Dilbeck

Files at this revision

API Documentation at this revision

Comitter:
ky3orr
Date:
Mon Nov 23 11:28:44 2015 +0000
Parent:
6:191569a26f50
Child:
8:3f5901f2f813
Commit message:
Code refactored to have MAX7219/7221 driver only with SPI chain support.

Changed in this revision

Max7221.cpp Show annotated file Show diff for this revision Revisions of this file
Max7221.h Show annotated file Show diff for this revision Revisions of this file
--- a/Max7221.cpp	Thu Nov 19 23:58:07 2015 +0000
+++ b/Max7221.cpp	Mon Nov 23 11:28:44 2015 +0000
@@ -1,230 +1,105 @@
 /**
 * @file Max7221.cpp
-* @brief This file defines the Max7221 class methods and the default values for static variables
+* @brief MAX7219/7221 driver class.
 * 
-* @author Dwayne S. Dilbeck
-*
-* @date 8/6/2013
+* @author Grzegorz Kaczmarek
+* @comment Code inspired on erlier Dwayne S. Dilbeck's work
+* @date 20/11/2015
 */
+
 #include "mbed.h"
 #include "Max7221.h"
 
-///Intialize the Class static members
-///Devices used per SPI bus are set to ZERO
-int Max7221::maxInUseSPI = 0;
-///Set the static pointers to the SPI busses to NULL
-SPI *Max7221::spi=NULL;
-///Set the static pointers to the load signals to NULL
-DigitalOut *Max7221::cs=NULL;
-
-/**
-*  Constructor. This is the default constructor
-*  @author Dwayne S. Dilbeck
-*  @param msoi  The SPI pin used as input to the device.       Valid values for LPC1768 are p5 or p11
-*  @param mclk  The SPI pin used as clock for the device.      Valid values for LPC1768 are p7 or p13
-*  @param load  The pin used to control load for the device.   Any pin capable for DigitalOut can be used, but the same load pin must be used for 
-*    device that share the same msoi and mclk pins
-*  @date 8/6/2013
-*/
-Max7221::Max7221(PinName msoi, PinName mclk, PinName load){
-  ///Set this insctance to pointers to the correct static pointers
-  this->id=maxInUseSPI;
-  this->maxInUse=&maxInUseSPI;
-  ///If no devices have been assigned to the SPI bus it must be initialized
-  if (spi ==NULL) {
-     spi = new SPI(msoi, NC, mclk);
-     cs = new DigitalOut(load);
-  }
-  this->max7221_spi= spi;
-  this->max7221_cs = cs;
+Max7221::Max7221(SPI *spi, DigitalOut *cs, unsigned int position) :
+    mp_spi(spi),
+    mp_cs(cs),
+    m_position(position)
+{
 }
 
-/**
-*  This method is used to write a byte of data to a specified register for only the device defined in this class instance
-*  @author Dwayne S. Dilbeck
-*  @param reg  The register to write to.
-*  @param data The value to be written.
-*  @date 8/6/2013   
-*//**
-*  This method is used to write a byte of data to a specified register for only the device defined in this class instance
-*  @author Dwayne S. Dilbeck
-*  @param reg  The register to write to.
-*  @param data The value to be written.
-*  @date 8/6/2013   
-*/
-void Max7221::Write( unsigned int reg, unsigned int data) {
-    int c = 0;
-    *cs = LOW;
-
-    ///if there are multiple devices sharing the SPI buss and they preceed the current device in the cascade Write a NOOP to them
-    for ( c = *maxInUse; c > this->id; c--) {
-        max7221_spi->write(0);  // no-op
-        max7221_spi->write(0);  // no-op
+void Max7221::CsLow()
+{
+    if(mp_cs != NULL) {
+        *mp_cs = LOG_0;
     }
-    ///Write to this device registers
-    max7221_spi->write(reg);  // specify register
-    max7221_spi->write(data);  // put data
-
-    ///if there are multiple devices sharing the SPI buss and they follow the current device in the cascade Write a NOOP to them
-    for ( c=this->id-1; c >= 1; c--) {
-        max7221_spi->write(0);  // no-op
-        max7221_spi->write(0);  // no-op
-    }
-    *cs = HIGH;
 }
 
-/**
-*  This method is used to write an  intial set off values to the device to prepare it for use.
-*  @author Dwayne S. Dilbeck
-*  @date 8/6/2013   
-*/   
-void Max7221::Setup () {
-    // initiation of the max 7221
-    // SPI setup: 8 bits, mode 0
-    max7221_spi->format(8, 0);
-    
-    // going by the datasheet, min clk is 100ns so theoretically 10MHz should work...
-    max7221_spi->frequency(10*MHZ);
-    
-    Write(max7219_reg_scanLimit, 0x07);   ///ENABLE all 8 digits
-    Write(max7219_reg_decodeMode, 0xff);  // Turn on Code B font decode for all digits
-    Write(max7219_reg_shutdown, 0x01);    // Disable shutdown mode
-    Write(max7219_reg_displayTest, 0x00); // Disable display test
-    for (int e=1; e<=8; e++) {            // Write blank to all digits
-        Write(e,0xf);
+void Max7221::CsHigh()
+{
+    if(mp_cs != NULL) {
+        *mp_cs = LOG_1;
     }
-    Write(max7219_reg_intensity, 0x01 );    // Set the display intensity to a low level. 
-                                                  // range: 0x00 to 0x0f
 }
 
-/**
-*  This method is used to write a byte of data to a specified register for all the devices instantiated.
-*  @author Dwayne S. Dilbeck
-*  @param reg  The register to write to.
-*  @param data The value to be written.
-*  @date 8/6/2013   
-*/   
-void Max7221::WriteAll (unsigned int reg, unsigned int data) {   
-    ///Write to all the devices on SPI Bus #1 first
-    if(cs !=NULL) {
-        *cs = LOW;                    // begin
-        for ( int c=1; c<= maxInUseSPI; c++) {
-            spi->write(reg);  // specify register
-            spi->write(data);  // put data
-        }
-        *cs = HIGH;
+void Max7221::WriteRaw(unsigned int reg, unsigned int data) {
+    if(mp_spi != NULL) {
+        mp_spi->write(reg);
+        mp_spi->write(data);
     }
 }
-/**
-*  This method is used to display an integer to the specified device instance. Underflow and overflow result in '-' written to all digits
-*  @author Dwayne S. Dilbeck
-*  @param value  An integer value to display
-*  @date 8/6/2013   
-*/   
-void Max7221::WriteInt( int value ){
-  char buffer[16];
-   
-  ///TODO:SET UPPERBOUND AND LOWERBOUND based on NUMDIGITS
-  ///Check the the INT value can be displayed and convert to a string.
-  if (value <= UPPERBOUND && value >= LOWERBOUND) {
-     sprintf(buffer,"%8d",value);
-  } else {
-     sprintf(buffer,"--------");
-  } 
-  ///In case a program changed the decode mode, set it again.
-  Write(max7219_reg_decodeMode, 0xff);
-  for (int i=0;i<NUMDIGITS;i++) {
-       ///For each character of the string, convert the ASCII to the datacode needed by the device
-       switch(buffer[i]){
-           case 0x2d: buffer[i]=0xa; break;
-           case 0x20: buffer[i]=0xf; break;
-           default: buffer[i]= buffer[i] & 0x0f;
-       }
-       ///Call function to write the data for each character of the srting.
-       Write(NUMDIGITS-i,buffer[i]);
-  }
+
+void Max7221::Write(unsigned int reg, unsigned int data) {
+    unsigned int i;
+    
+    CsLow();
+    WriteRaw(reg, data);
+    if(m_position > 0) {
+        i = m_position;
+        while(i--) {
+            WriteRaw(max7219_reg_noop, 0x0);
+        }
+    }
+    CsHigh();
+}
+
+void Max7221::TestMode(bool mode) {
+    if(mode) {
+        Write(max7219_reg_displayTest, 0x01);
+    } else {
+        Write(max7219_reg_displayTest, 0x00);
+    }
+}
+
+void Max7221::UseDigitsNo(unsigned int digits_no) {
+    if((digits_no > 0) && (digits_no < 9)) {
+        Write(max7219_reg_scanLimit, (digits_no - 1));
+    }
+}
+
+void Max7221::DecodeMode(unsigned int mode) {
+    Write(max7219_reg_decodeMode, mode);
 }
 
-/**
-*  This method is used to display a floating point number to the specified device instance. 
-*   Underflow and overflow result in '-' written to all digits. The digits after the decimal 
-*   point are truncated to fit the display.
-*  @author Dwayne S. Dilbeck
-*  @param value  A float value to display
-*  @date 8/6/2013   
-*/   
-void Max7221::WriteFloat( float value ){
-  char buffer[32];
-  int ptr=-1,len;
-  int i;
- 
-  sprintf(buffer,"%f",value);
-  len=strlen(buffer);
-  i=len-1;
-  while(buffer[i]==0x30) {
-     buffer[i]='\0';
-     i--;
-     len--;
-  }
-  for( i =0; i<=len; i++) {
-      switch(buffer[i]){
-               case 0x2d: buffer[i]=0xa; break;
-               case 0x20: buffer[i]=0xf; break;
-               case 0x2e: buffer[i]=buffer[i-1] | 0x80;
-                           ptr = i-1;
-                           break;
-               default: buffer[i]= buffer[i];
-      }       
-      if (ptr != -1) {
-        buffer[i-1]=buffer[i]; 
-     }
-  }
-     
-  len=strlen(buffer);
-  Write(max7219_reg_decodeMode, 0xff);
+void Max7221::WriteDigit(unsigned int digit_no, unsigned int value) {
+    if(digit_no < 8) {
+        Write(digit_no, value);
+    }
+}
 
-  // If too large for display set to '-'
-  if(len > NUMDIGITS && (ptr==-1 || ptr>NUMDIGITS))
-        for (int i=0;i<NUMDIGITS;i++) {
-           buffer[i]=0x0a;
-        }
-  //if number is smaller than display, fill with ' '      
-  if (len<=NUMDIGITS) { 
-      for (int i=1;i<=NUMDIGITS;i++) {
-           if(len-i>=0) {
-             Write(i,buffer[len-i]);
-           } else {
-             Write(i,0xf);   
-           }
-      }
-  } else {
-  //Write out the buffer, truncating the decimal digits if larger than display
-      for (int i=0;i<NUMDIGITS;i++) {
-          Write(NUMDIGITS-i,buffer[i]);
-      }
-  }
+void Max7221::Intensity(unsigned int intensity) {
+    if(intensity > 0x0F) {
+        intensity = 0x0F;
+    }
+    Write(max7219_reg_intensity, intensity);
 }
 
-/**
-*  This method is used to write an intial set off values to ALL device to prepare them for use.
-*  @author Dwayne S. Dilbeck
-*  @date 8/6/2013   
-*/   
-void Max7221::SetupAll () {
-    // initiation of the max 7219
-    // SPI setup: 8 bits, mode 0
-    if(spi!=NULL) {
-       spi->format(8, 0);
-       spi->frequency(10*MHZ);    
-    }               
-    WriteAll(max7219_reg_scanLimit, 0x07);
-    WriteAll(max7219_reg_decodeMode, 0xff);  // using an led matrix (not digits)
-    WriteAll(max7219_reg_shutdown, 0x01);    // not in shutdown mode
-    WriteAll(max7219_reg_displayTest, 0x00); // no display test
-    for (int e=1; e<=8; e++) {            // empty registers, turn all LEDs off
-        WriteAll(e,0xf);
+void Max7221::OperationMode(bool mode) {
+    if(mode) {
+        Write(max7219_reg_shutdown, 0x01);
+    } else {
+        Write(max7219_reg_shutdown, 0x00);
     }
-    WriteAll(max7219_reg_intensity, 0x01 & 0x0f);    // the first 0x0f is the value you can set
-                                                  // range: 0x00 to 0x0f
 }
 
+void Max7221::Setup () {
+    unsigned int i;
+
+    TestMode(false);            // Disable display test
+    UseDigitsNo(8);             // Use all 8 digits
+    DecodeMode(0xFF);           // Turn on Code B font decode for all digits
+    for(i=1;i<9;i++) {          // Clean all digits
+        WriteDigit(i, 0x0F);
+    }
+    Intensity(0x01);            // Set lowest display intensity(0x00-0xFF)
+    OperationMode(true);        // Enable operation mode
+}
--- a/Max7221.h	Thu Nov 19 23:58:07 2015 +0000
+++ b/Max7221.h	Mon Nov 23 11:28:44 2015 +0000
@@ -1,179 +1,108 @@
 /**
 * @file Max7221.h
-* @brief This file contains the class defnition of Max7221 and define statements related to the class, and max7221 device
-* The methods in this class are derived from posts on the mbed forum written by Igor Skochinsky on October 2009
+* @brief Header file for the MAX7219/7221 driver class.
 * 
-* @author Dwayne S. Dilbeck
-*
-* @date 8/6/2013
+* @author Grzegorz Kaczmarek
+* @comment Code inspired on erlier Dwayne S. Dilbeck's work
+* @date 20/11/2015
 */
+
 #ifndef Max7221_H
 #define Max7221_H
 
-
-// define max7219/max7221 registers
+// MAX7219/7221 register map
 #define max7219_reg_noop         0x00
-#define max7219_reg_digit0       0x01
-#define max7219_reg_digit1       0x02
-#define max7219_reg_digit2       0x03
-#define max7219_reg_digit3       0x04
-#define max7219_reg_digit4       0x05
-#define max7219_reg_digit5       0x06
-#define max7219_reg_digit6       0x07
-#define max7219_reg_digit7       0x08
 #define max7219_reg_decodeMode   0x09
 #define max7219_reg_intensity    0x0a
 #define max7219_reg_scanLimit    0x0b
 #define max7219_reg_shutdown     0x0c
 #define max7219_reg_displayTest  0x0f
 
-#define LOW 0
-#define HIGH 1
-#define MHZ 1000000
-#define NUMDIGITS 8
-
-#ifdef NUMDIGITS 
-#define UPPERBOUND 99999999
-#define LOWERBOUND -9999999
-#endif
+// Logical values
+#define LOG_0 0
+#define LOG_1 1
 
-/**
- * Max7221 Example
- * @code
- * #include "mbed.h"
- * #include "Max7221.h"
- *  
- * 
- * // p5: DIN, p7: CLK, p8: LOAD/CS
- * Max7221 max7221disp1(p5, p7, p8);
- * //Max7221 max7221disp2(p5, p7, p8);
- * //Max7221 max7221disp3(p11, p13, p14);
- * //Max7221 max7221disp4(p11, p13, p14);
- * 
- * int count=-99;
- * 
- * void loop(void) {
- *    max7221disp1.WriteInt(count);
- *    if (count < 100)
- *       count=count+1;
- *    else 
- *      count=-99; 
- * }
- * 
- * int main() {  
- *     max7221disp1.Setup();
- *     //Max7221::SetupALl();
- *     max7221disp1.WriteFloat(123.125);
- *     wait(1.0);  
- * 
- *     while (1) {
- *         loop(); 
- *         wait(1.0);
- *     }
- * }
- * @endcode
- */
 class Max7221 {
+private:
+   SPI *mp_spi;             // SPI used for this display (no data transmission when NULL)
+   DigitalOut *mp_cs;       // CS signal (it should be handled manually when NULL)
+   unsigned int m_position; // Display position on SPI chain (0 = 1'st)
+
 public:
     /**
-    *  Constructor. This is the default constructor
-    *  @author Dwayne S. Dilbeck
-    *  @param msoi  The SPI pin used as input to the device.       Valid values for LPC1768 are p5 or p11
-    *  @param mclk  The SPI pin used as clock for the device.      Valid values for LPC1768 are p7 or p13
-    *  @param load  The pin used to control load for the device.   Any pin capable for DigitalOut can be used, but the same load pin must be used for 
-    *    device that share the same msoi and mclk pins
-    *  @date 8/6/2013
+    *  Default constructor.
+    *  @param spi       Initialized SPI port used for communication with MAX7219/7221.
+    *  @param cs        Initialized output pin used as SW CS signal or NULL when HW one is used.
+    *  @param position  Position on SPI port (for displays connected in daisy-chain: DOUT-DIN). 0=1st.
+    */
+    Max7221(SPI *spi, DigitalOut *cs, unsigned int position=0);
+
+    /**
+    *  Method for setting /CS signal LOW (enable data reception).
     */
-    Max7221(PinName msoi=PTC6, PinName mclk=PTC5, PinName load=PTC4);
+    void CsLow(void);
+
+    /**
+    *  Method for setting /CS signal HIGH (received data is latched and processed).
+    */
+    void CsHigh(void);
+
+    /**
+    *  Method used to send data over SPI (no use of /CS signal).
+    *  To be used with display chains and when building display libraries
+    *  where amount of data needs to be pushed via SPI in one transaction.
+    */
+    void WriteRaw(unsigned int reg, unsigned int data);
    
     /**
-    *  This method is used to write a byte of data to a specified register for only the device defined in this class instance
-    *  @author Dwayne S. Dilbeck
-    *  @param reg  The register to write to.
-    *  @param data The value to be written.
-    *  @date 8/6/2013   
+    *  Method for sending register-value pair for this diasplay.
+    *  Supports display chain on single SPI (m_position > 0).
     */
-    void Write( unsigned int reg, unsigned int data);
+    void Write(unsigned int reg, unsigned int data);
 
     /**
-    *  This method is used to display an integer to the specified device instance. Underflow and overflow result in '-' written to all digits
-    *  @author Dwayne S. Dilbeck
-    *  @param value  An integer value to display
-    *  @date 8/6/2013   
-    */   
-    void WriteInt( int value );
+    *  Sets test mode which causes all display LEDs to emit light with full brightess.
+    *  @param mode  true - test mode, false - normal operation.
+    */
+    void TestMode(bool mode);
+    
+    /**
+    *  Sets amount of digits to be used by this display.
+    *  @param digits_no  1 - one digit, (2-7), 8 - all 8 digits.
+    */
+    void UseDigitsNo(unsigned int digits_no);
 
     /**
-    *  This method is used to display a floating point number to the specified device instance. 
-    *   Underflow and overflow result in '-' written to all digits. The digits after the decimal 
-    *   point are truncated to fit the display.
-    *  @author Dwayne S. Dilbeck
-    *  @param value  A float value to display
-    *  @date 8/6/2013   
-    */   
-    void WriteFloat( float value);
-   
-    /**
-    *  Overload of the EQUALS operator to provide easy use of the class.
-    *  @author Dwayne S. Dilbeck
-    *  @param value  An integer value to display
-    *  @date 8/6/2013   
-    */      
-    Max7221& operator= (int value){ 
-        WriteInt(value); 
-        return *this;
-        };
-    /**
-    *  Overload of the EQUALS operator to provide easy use of the class.
-    *  @author Dwayne S. Dilbeck
-    *  @param value  A float value to display
-    *  @date 8/6/2013   
-    */   
-    Max7221& operator= (float value){ 
-        WriteFloat(value); 
-        return *this; 
-        };
+    *  Selects for which digits Code-B data decoding is used.
+    *  @param mode  0x00 - no decoding, 0x0F - digits 0-3, 0xFF - all digits.
+    */
+    void DecodeMode(unsigned int mode);
 
     /**
-    *  This method is used to write an  intial set off values to the device to prepare it for use.
-    *  @author Dwayne S. Dilbeck
-    *  @date 8/6/2013   
-    */   
-    void Setup (void);
-
-    /**
-    *  This method is used to write a byte of data to a specified register for all the devices instantiated.
-    *  @author Dwayne S. Dilbeck
-    *  @param reg  The register to write to.
-    *  @param data The value to be written.
-    *  @date 8/6/2013   
-    */   
-    static void WriteAll (unsigned int reg, unsigned int data);
+    *  Sends data to selected digit.
+    *  @param digit_no  Selected digit (0-7).
+    *  @param digit_no  Data to display.
+    */
+    void WriteDigit(unsigned int digit_no, unsigned int value);
 
     /**
-    *  This method is used to write an intial set off values to ALL device to prepare them for use.
-    *  @author Dwayne S. Dilbeck
-    *  @date 8/6/2013   
+    *  Sets display brightness.
+    *  @param intensity  0x00 - minimum brightness, 0x0F - maximum brightness.
+    */
+    void Intensity(unsigned int intensity);
+
+    /**
+    *  Sets display operation mode.
+    *  @param mode  true - normal operation, false - shutdown mode.
+    */
+    void OperationMode(bool mode);
+    
+    /**
+    *  Initial setup of this display.
+    *  8-digit blank decimal display set to nimimal brightness.
+    *  Supports display chain on single SPI (m_position > 0).
     */   
-    static void SetupAll (void);
-   
-private:
-   /// Pointer for the class instance to a particular SPI bus
-   SPI *max7221_spi;
-   /// pointer for the class instance of a particular load signal
-   DigitalOut *max7221_cs;
-   ///  id of the class instance
-   int id;
-   /// pointer to the number of devices connected to the SPI bus instance this device instance is connected to.
-   int *maxInUse;
-   
-   ///For the class we have a static set of values.  There are 2 SPI buses, 2 load signals, and 2 counters of the number of devices connected to a SPI bus.
-   static SPI *spi;
-//   static SPI *spi2;
-   static DigitalOut *cs;
-//   static DigitalOut *load2;
-   static int maxInUseSPI;
-//   static int maxInUseSPI2;
+    void Setup(void);
 };
 
 #endif
\ No newline at end of file