MAX7221

MAX7219.MAX7221 History

Hide minor edits - Show changes to output

Changed line 48 from:
*  Author  : Ahmed Lazreg  ([email protected].com)                         *
to:
*  Author  : Ahmed Lazreg  (ahmed.[email protected]com)                  *
Changed line 122 from:
*  Author  : Ahmed Lazreg  ([email protected].com)                         *
to:
*  Author  : Ahmed Lazreg  (ahmed.[email protected]com)                  *
Changed line 211 from:
*  Author  : Ahmed Lazreg  ([email protected].com)                         *
to:
*  Author  : Ahmed Lazreg  (ahmed.[email protected]com)                  *
Changed line 106 from:
       WriteValue(DecToStr(i))
to:
       WriteValue(DecToStr(i))   ' use FloatToStr(..) for floating point values
Changed line 1 from:
'''Maxim Integrated(tm) MAX7219/MAX7221'''
to:
!!!Maxim Integrated(tm) MAX7219/MAX7221
Changed line 12 from:
!!!Main Features of Swordfish MAX7219/MAX7221 module :'''
to:
!!!Main Features of Swordfish MAX7219/MAX7221 module :
Changed lines 11-12 from:
'''Main Features of Swordfish MAX7219/MAX7221 module :'''
to:

!!!Main Features of Swordfish MAX7219/MAX7221 module :'''
Changed lines 40-41 from:
!!!Example Code
!!!Example Code
to:
!!!Example Code for single MAX7219 module
Added lines 112-113:

!!!Example Code two (02) cascaded MAX7219 modules
Changed line 11 from:
'''Main Features:'''
to:
'''Main Features of Swordfish MAX7219/MAX7221 module :'''
Added line 1:
'''Maxim Integrated(tm) MAX7219/MAX7221'''
Added lines 9-10:
http://www.pocketmt.com/images/max7219.png
Deleted lines 35-36:
!!Single MAX7219 chip module connection
Changed lines 38-40 from:
http://www.pocketmt.com/images/max7219.png

!!!Module Code
to:
??? diagram (coming soon)

!!!Example Code
!!!Example Code
This program uses 2 MAX7219 modules, each handling 8 7Seg display module.

Changed lines 55-58 from:
Modified:                                                           *
*
  Notes  : This module handles Maxime Integrated(TM) MAX7219/MAX7221  *
*
            Serially Interfaced, 8-Digit LED Display Drivers          *
*            It can be used via Hardware or Software SPI modules
        *
to:
Desc.  : Test program for MAX7219 module                            *
*
                                                                      *
Changed lines 60-62 from:

Module MAX7219

to:
Program Max7219_test

Device = 18F452
Clock = 20

Include "utils.bas"
Changed lines 67-135 from:
Include "string.bas"

// Number of cascaded display modules
#if IsOption(MAX7219_DISP_COUNT) And Not (MAX7219_DISP_COUNT > 0)
  #error MAX7219_DISP_COUNT, "Invalid option, must be > 0"
#endif
#option MAX7219_DISP_COUNT = 1

Const MAX7219_DISPLAY_COUNT = MAX7219_DISP_COUNT
// hardware or software SPI...
#if IsOption(MAX7219_SPI_SOFTWARE) And Not (MAX7219_SPI_SOFTWARE in (true, false))
  #error MAX7219_SPI_SOFTWARE, "Invalid option, must be TRUE or FALSE."
#endif
#option MAX7219_SPI_SOFTWARE = false


#if MAX7219_SPI_SOFTWARE = true // use software SPI...
Include "sspi.bas"
#else // use hardware SPI...
Include "SPI.BAS"
#EndIf

#Option MAX7219_CS  = PORTC.1

// validate SCK pin...
#If IsOption(MAX7219_CS) And Not IsValidPortPin(MAX7219_CS)
  #Error MAX7219_CS, "Invalid option. MCP_CS must be a valid port pin."
#EndIf

Public Dim
  CS As [email protected]  // Chip select

' To be used with WriteDigit(...) subroutine
' for digits (0..9) just send the digit itself
' for non-digits, use codes below as pValue param in WriteDigit(...)
Public Const
    SYMB_DASH  As Byte = $A, ' displays "-" symbol
    SYMB_E    As Byte = $B, ' displays "E" symbol
    SYMB_H    As Byte = $C, ' displays "H" symbol
    SYMB_L    As Byte = $D, ' displays "L" symbol
    SYMB_P    As Byte = $E, ' displays "P" symbol
    SYMB_BLANK As Byte = $F  ' blanks the digit

' Internal registers of the MAX7219
Private Const
    REG_NO_OP      As Byte = $00,
    REG_DIGIT(8)    As Byte = ($01, $02, $03, $04, $05, $06, $07, $08),
    REG_DECODE_MODE As Byte = $09,
    REG_INTENSITY  As Byte = $0A,
    REG_SCAN_LIMIT  As Byte = $0B,
    REG_SHUTDOWN    As Byte = $0C,
    REG_DISP_TEST  As Byte = $0F

Private Dim fSelectedDisp As Byte

{
****************************************************************************
* Name    : SelectDisplay                                                  *
* Purpose : Selects active display                                        *
* param  : pDisplayIndex = display index.                                *
*            - First display module = 0                                  *
*            - pDisplayIndex must be < MAX7219_DISP_COUNT                *
****************************************************************************
}
Public Sub SelectDisplay(pDisplayIndex As Byte)
    If pDisplayIndex >= MAX7219_DISPLAY_COUNT Then
        pDisplayIndex = MAX7219_DISPLAY_COUNT
    EndIf
    fSelectedDisp = pDisplayIndex
to:

//#option MAX7219_SPI_SOFTWARE = true
Include "Max7219.bas"

Dim RED_LED    As PORTB.1

Dim i As Word

Sub Init_MCU()
    PORTA = %00000000
    TRISA = %11111100
    PORTB = %00000000
    TRISB = $00
    SetAllDigital()
Added lines 83-116:
Init_MCU()
High(RED_LED)

// main program loop
SetDisplayTestMode(true)
DelayMS(300)
SetDisplayTestMode(false)
WriteDigit(6, SYMB_E)
WriteDigit(7, SYMB_P)
DelayMS(1000)

BlankDisplay()
WriteValue("HELP-. ")

DelayMS(1000)

BlankDisplay()
WriteDigit(7, SYMB_H)

i = 0
While (true)
        Toggle(RED_LED)
        DelayMS(800)
        WriteValue(DecToStr(i))
        i = i +1
End While

End Program
=]


This program uses 2 cascaded MAX7219 modules, each handling 8 7Seg display module.

=code [=
Changed lines 118-152 from:
****************************************************************************
*
Name    : GetSelectedDisplay()                                          *
* Purpose : returns actually selected Max7219 module
                     *
****************************************************************************
}

Public Function GetSelectedDisplay() As Byte
    result = fSelectedDisp
End Function

' MAX7219 command format is

' [D15][D14][D13][D12] [D11 -  D8] [D7  -    D0]
' [ x ][ x ][ x ][ x ] [ REG_ADDR] [msb DATA lsb]

{
****************************************************************************
* Name
    : WriteReg                                                      *
* Purpose : Writes pData byte to register address given by pRegAddress    *
****************************************************************************
}
Public Sub WriteReg
(pRegAddress As Byte, pData As Byte)
    Dim i, count As Byte
    CS = 0  ' must be set here mainly because of Max7221
    count = MAX7219_DISPLAY_COUNT-fSelectedDisp-1
    For i = 1 To count
        WriteByte(REG_NO_OP)
        WriteByte($00)
    Next
    WriteByte(pRegAddress)
    WriteByte(pData)
    count = fSelectedDisp
    For i = 1 To count
        WriteByte(REG_NO_OP)
        WriteByte($00)
    Next
    CS = 1
to:
*************************************************************************
*  Name    : MAX7219.BAS                                                *
*  Author
  : Ahmed Lazreg  ([email protected])                       *
*           http://www.pocketmt.com                                    *
*           http://www.microcodeproject.com                            *
*  Notice  : Copyright (c) 20015 Pocket MicroTechnics                  *
*         : All Rights Reserved                                        *
*  Date    : 01/01/2015                                                *
*  Version : 1.0                                                        *
*  Desc.  : Test program for MAX7219 module                            *
                                                                   *
*************************************************************************
}

Program Max7219_test

Device = 18F452
Clock = 20

Include "utils.bas"
Include "convert.bas"

//#option MAX7219_SPI_SOFTWARE = true
#option MAX7219_DISP_COUNT = 2
Include "Max7219.bas"

Dim RED_LED
    As PORTB.1

Dim i, j As Word

Dim k As Float
Sub Init_MCU()
    PORTA = %00000000
    TRISA = %11111100
    PORTB = %00000000
    TRISB = $00
    SetAllDigital()
Added lines 156-205:


Init_MCU()
High(RED_LED)

// main program loop
SelectDisplay(0)
SetDisplayTestMode(true)
DelayMS(300)
SetDisplayTestMode(false)
SelectDisplay(0)
WriteDigit(6, SYMB_E)
WriteDigit(7, SYMB_P)
DelayMS(1000)

SelectDisplay(0)
BlankDisplay()
WriteValue("HELP-. ")

SelectDisplay(1)
WriteValue("-41.73")
DelayMS(1000)

SelectDisplay(0)
BlankDisplay()
WriteValue("HELP    ")

SelectDisplay(1)
BlankDisplay()
WriteDigit(7, SYMB_L)

i = 0
j = 0
k = 0.0
While (true)
        Toggle(RED_LED)
        DelayMS(800)
        SelectDisplay(0)
        WriteValue(DecToStr(i))
        SelectDisplay(1)
        WriteValue(FloatToStr(k))
        i = i +1
        k = k + 0.2
End While

End Program
=]

!!!Module Code
=code [=
Added lines 207-282:
*************************************************************************
*  Name    : MAX7219.BAS                                                *
*  Author  : Ahmed Lazreg  ([email protected])                        *
*            http://www.pocketmt.com                                    *
*            http://www.microcodeproject.com                            *
*  Notice  : Copyright (c) 20015 Pocket MicroTechnics                  *
*          : All Rights Reserved                                        *
*  Date    : 01/01/2015                                                *
*  Version : 1.0                                                        *
*  Modified:                                                            *
*  Notes  : This module handles Maxime Integrated(TM) MAX7219/MAX7221  *
*            Serially Interfaced, 8-Digit LED Display Drivers          *
*            It can be used via Hardware or Software SPI modules        *
*************************************************************************
}


Module MAX7219

Include "convert.bas"
Include "string.bas"

// Number of cascaded display modules
#if IsOption(MAX7219_DISP_COUNT) And Not (MAX7219_DISP_COUNT > 0)
  #error MAX7219_DISP_COUNT, "Invalid option, must be > 0"
#endif
#option MAX7219_DISP_COUNT = 1

Const MAX7219_DISPLAY_COUNT = MAX7219_DISP_COUNT
// hardware or software SPI...
#if IsOption(MAX7219_SPI_SOFTWARE) And Not (MAX7219_SPI_SOFTWARE in (true, false))
  #error MAX7219_SPI_SOFTWARE, "Invalid option, must be TRUE or FALSE."
#endif
#option MAX7219_SPI_SOFTWARE = false


#if MAX7219_SPI_SOFTWARE = true // use software SPI...
Include "sspi.bas"
#else // use hardware SPI...
Include "SPI.BAS"
#EndIf

#Option MAX7219_CS  = PORTC.1

// validate SCK pin...
#If IsOption(MAX7219_CS) And Not IsValidPortPin(MAX7219_CS)
  #Error MAX7219_CS, "Invalid option. MCP_CS must be a valid port pin."
#EndIf

Public Dim
  CS As [email protected]  // Chip select

' To be used with WriteDigit(...) subroutine
' for digits (0..9) just send the digit itself
' for non-digits, use codes below as pValue param in WriteDigit(...)
Public Const
    SYMB_DASH  As Byte = $A, ' displays "-" symbol
    SYMB_E    As Byte = $B, ' displays "E" symbol
    SYMB_H    As Byte = $C, ' displays "H" symbol
    SYMB_L    As Byte = $D, ' displays "L" symbol
    SYMB_P    As Byte = $E, ' displays "P" symbol
    SYMB_BLANK As Byte = $F  ' blanks the digit

' Internal registers of the MAX7219
Private Const
    REG_NO_OP      As Byte = $00,
    REG_DIGIT(8)    As Byte = ($01, $02, $03, $04, $05, $06, $07, $08),
    REG_DECODE_MODE As Byte = $09,
    REG_INTENSITY  As Byte = $0A,
    REG_SCAN_LIMIT  As Byte = $0B,
    REG_SHUTDOWN    As Byte = $0C,
    REG_DISP_TEST  As Byte = $0F

Private Dim fSelectedDisp As Byte

{
Changed lines 284-298 from:
* Name    : SetDecodeMode                                                  *
* Purpose : Sets de Max7219 decode mode for each digit                    *
* param
  : pDecodeMask = a 8 bit value. Setting  bit to 0/1              *
*
          disables/enables the B-Decoding for concerned digit            *
                                                                         *
            When the code B decode mode is used, the decoder              *
            looks only at the lower nibble of the data in the digit        *
            registers (D3D0), disregarding bits D4D6. D7, which          *
            sets the decimal point (SEG DP), is independent of the        *
            decoder and is positive logic (D7 = 1 turns the decimal        *
            point on).                                                    *
            When no-decode is selected, data bits D7D0 correspond        *
            to the segment lines of the MAX7219/MAX7221.                  *
            Table 6 shows the one-to-one pairing of each data bit          *
            to the appropriate segment line.             
                *
to:
* Name    : SelectDisplay                                                  *
* Purpose : Selects active display                                       *
* param
  : pDisplayIndex = display index.                                 *
*            - First display module = 0                                  *
*
            - pDisplayIndex must be < MAX7219_DISP_COUNT                *
Changed lines 291-292 from:
Public Inline Sub SetDecodeMode(pDecodeMask As Byte)
    WriteReg(REG_DECODE_MODE, pDecodeMask)
to:
Public Sub SelectDisplay(pDisplayIndex As Byte)
    If pDisplayIndex >= MAX7219_DISPLAY_COUNT Then
        pDisplayIndex = MAX7219_DISPLAY_COUNT
    EndIf
    fSelectedDisp = pDisplayIndex
Changed lines 300-301 from:
* Name    : DisplayOn                                                     *
* Purpose : Enables the display                   
                      *
to:
* Name    : GetSelectedDisplay()                                          *
* Purpose : returns actually selected Max7219 module
                      *
Changed lines 304-307 from:
Public Inline Sub DisplayOn()
    WriteReg(REG_SHUTDOWN, $1)
End Sub

to:
Public Function GetSelectedDisplay() As Byte
    result = fSelectedDisp
End Function

' MAX7219 command format is
' [D15][D14][D13][D12] [D11 -  D8] [D7  -    D0]
' [ x ][ x ][ x ][ x ] [ REG_ADDR] [msb DATA lsb]

Changed lines 314-315 from:
* Name    : DisplayOff                                                    *
* Purpose : Shuts down the display                                        *
to:
* Name    : WriteReg                                                      *
* Purpose : Writes pData byte to register address given by pRegAddress    *
Changed lines 318-319 from:
Public Inline Sub DisplayOff()
    WriteReg(REG_SHUTDOWN, $0
)
to:
Public Sub WriteReg(pRegAddress As Byte, pData As Byte)
    Dim i, count As Byte
    CS = 0  ' must be set here mainly because of Max7221
    count = MAX7219_DISPLAY_COUNT-fSelectedDisp-1
    For i = 1 To count
        WriteByte(REG_NO_OP)
        WriteByte($00)
    Next
    WriteByte(pRegAddress)
    WriteByte(pData)
    count = fSelectedDisp
    For i = 1 To count
        WriteByte(REG_NO_OP)
        WriteByte($00)
    Next
    CS = 1
Changed lines 338-353 from:
* Name    : SetNumberOfDigits                                              *
* Purpose : Sets the number of digits availble in the display 
          *
* param
  : pNumberOfDigits = value from  1 to 8                         *
*                                                                         *
*
          WARNING:::: DANGEOUROUS !!!!!                                 *
                                                                    *
*
          If the scan-limit register is set for three digits or less,    *
*
          individual digit drivers will dissipate excessive amounts     *
*
         of power. Consequently, the value of the RSET resistor         *
*
          must be adjusted according to the number of digits displayed,  *
*
          to limit individual digit driver power dissipation.            *
*                                                                        *
* This function has been added only for debug purpose or 
                *
* - when the Max7219 is used a LED driver (i
.e Decode mode disabled)      *
* - when the Max7219 is cascaded with another Max7219 that is used to      *
*  less than 8 digits                     
                              *
to:
* Name    : SetDecodeMode                                                 *
* Purpose : Sets de Max7219 decode mode for each digit
                     *
* param
  : pDecodeMask = a 8 bit value. Setting  bit to 0/1               *
*          disables/enables the B-Decoding for concerned digit            *
                                                                         *
            When the code B decode mode is used, the decoder              *
            looks only at the lower nibble of the data in the digit        *
            registers (D3D0), disregarding bits D4D6. D7, which          *
           sets the decimal point (SEG DP), is independent of the        *
         decoder and is positive logic (D7 = 1 turns the decimal       *
   
        point on).                                                  *
            When no-decode is selected, data bits D7D0 correspond        *
            to the segment lines of the MAX7219/MAX7221.                  *
            Table 6 shows the one-to-one pairing of each data bit          *
           to the appropriate segment line.                              *
Changed lines 355-361 from:
Public Sub SetNumberOfDigits(pNumberOfDigits As Byte)
    If pNumberOfDigits > 8 Then
        pNumberOfDigits = 8
    ElseIf pNumberOfDigits < 1 Then
        pNumberOfDigits = 1
    EndIf
    WriteReg(REG_SCAN_LIMIT, pNumberOfDigits-1
)
to:
Public Inline Sub SetDecodeMode(pDecodeMask As Byte)
    WriteReg(REG_DECODE_MODE, pDecodeMask)
Changed lines 361-363 from:
* Name    : SetBrightness                                                  *
* Purpose : Sets de Max7219 brightness 
                                  *
* param  : pIntensity = a 8 bit value between 0 to 15 (16 steps)
          *
to:
* Name    : DisplayOn                                                     *
* Purpose : Enables the display
                                            *
Changed lines 365-366 from:
Public Inline Sub SetBrightness(pIntensity As Byte)
    WriteReg(REG_INTENSITY, (pIntensity And $F))
to:
Public Inline Sub DisplayOn()
 
  WriteReg(REG_SHUTDOWN, $1)
Changed lines 371-373 from:
* Name    : SetDisplayTestMode                                            *
* Purpose : Enables/Disables de Max7219 test mode
                         *
* param
  : pDispTestEnabled = True/False to Enable/Disable test mode      *
to:
* Name    : DisplayOff                                                     *
* Purpose : Shuts down the display
                                         *
Changed lines 375-380 from:
Public Sub SetDisplayTestMode(pDispTestEnabled As Boolean)
    If pDispTestEnabled Then
        WriteReg(REG_DISP_TEST, 1
)
    Else
        WriteReg(REG_DISP_TEST, 0)
    EndIf
to:
Public Inline Sub DisplayOff()
 
  WriteReg(REG_SHUTDOWN, $0)
Changed lines 381-400 from:
* Name    : WriteDigit                                                   *
* Purpose : writes a value to position pDigitPos
                         *
* param
  : pDigitPos = digit position from 0 to 7                        *
*
          pValue    = value to write to at pDigitPos digit position      *
                        * values from 0 to 9 displays corresponding digit  *
                       * $A = displays "-" symbol                        *
                        * $B = displays "E" symbol                        *
                       * $C = displays "H" symbol                      *
                       * $D = displays "L" symbol                        *
                     * $E = displays "P" symbol                        *
                        * $F = blanks the digit                           *
 
                     Use the constants defined at top of this module    *
                         SYMB_DASH  As Byte = $A, ' displays "-" symbol  *
                          SYMB_E    As Byte = $B, ' displays "E" symbol  *
                         SYMB_H    As Byte = $C, ' displays "H" symbol  *
                          SYMB_L    As Byte = $D, ' displays "L" symbol  *
                          SYMB_P    As Byte = $E, ' displays "P" symbol  *
                          SYMB_BLANK As Byte = $F  ' blanks the digit      *
                                                                          *
*          pDecimalPointOn = True/False Switch On/Off decimal point led
  *
to:
* Name    : SetNumberOfDigits                                              *
* Purpose : Sets the number of digits availble in the display   
          *
* param
  : pNumberOfDigits = value from  1 to 8                           *
*
                                                                        *
        WARNING:::: DANGEOUROUS !!!!!                                  *
*
                                                                          *
*
          If the scan-limit register is set for three digits or less,    *
*
          individual digit drivers will dissipate excessive amounts      *
*
          of power. Consequently, the value of the RSET resistor        *
*
          must be adjusted according to the number of digits displayed,  *
*          to limit individual digit driver power dissipation.            *
*
                                                                          *
* This function has been added only for debug purpose or
                  *
* - when
the Max7219 is used a LED driver (i.e Decode mode disabled)      *
* - when the Max7219 is cascaded with another Max7219 that is used to
      *
*
  less than 8 digits                                                   *
Changed lines 399-401 from:
Public Sub WriteDigit(pDigitPos As Byte, pValue As Byte, pDecimalPointOn As Boolean = false)
    pValue.Booleans(7) = pDecimalPointOn
   WriteReg(REG_DIGIT(pDigitPos), pValue)
to:
Public Sub SetNumberOfDigits(pNumberOfDigits As Byte)
    If pNumberOfDigits > 8 Then

      pNumberOfDigits = 8
    ElseIf pNumberOfDigits < 1 Then
        pNumberOfDigits = 1
    EndIf
    WriteReg(REG_SCAN_LIMIT, pNumberOfDigits-1
)
Changed lines 410-413 from:
* Name    : BlankDisplay                                                   *
* Purpose : Writes blank to each digit of the display                      *
* Note
    : this is **NOT** the same as DisplayOff() which puts the disp  *
        in shutdown mode                                               *  
to:
* Name    : SetBrightness                                                  *
* Purpose : Sets de Max7219 brightness                                   *
* param  : pIntensity = a 8 bit value between 0 to 15 (16 steps)          *
Changed lines 415-419 from:
Public Sub BlankDisplay()
 
  Dim i As Byte
    For i = 0 To 7
      WriteDigit(i,
$F, false)
   Next
to:
Public Inline Sub SetBrightness(pIntensity As Byte)
    WriteReg(REG_INTENSITY, (pIntensity And $F))
Changed lines 421-425 from:
* Name    : WriteValue                                                     *
* Purpose : Writes a value to the display.
                                 *
* Param  : pStr = string containing a formate value to display            *
*          Blanks and special symbols ("-", "H", "L", "E", "P", " ", "."  *
*          are handled  automatically by this routine             
      *
to:
* Name    : SetDisplayTestMode                                            *
* Purpose : Enables/Disables de Max7219 test mode
                         *
* param
  : pDispTestEnabled = True/False to Enable/Disable test mode      *
Changed lines 426-452 from:
Public Sub WriteValue(pStr As String)
  Dim i, value, curDigit As Byte
  Dim NextDigitHasDecPoint As Boolean
  NextDigitHasDecPoint = false
  curDigit = 0 'Length(pStr)-1
  For i = Length(pStr)-1 To 0 Step -1
    value = pStr(i)
      If value = 45 Then  ' "-"
          value = SYMB_DASH
      ElseIf value = 32 Then  ' " "
          value = SYMB_BLANK
      ElseIf value = 72 Then  ' "H"
          value = SYMB_H
      ElseIf value = 76 Then  ' "L"
          value = SYMB_L
      ElseIf value = 69 Then  ' "E"
          value = SYMB_E
      ElseIf value = 80 Then  ' "P"
          value = SYMB_P
      ElseIf value = 46 Then  ' "."
          NextDigitHasDecPoint = true
          Continue
      EndIf
      WriteDigit(curDigit, value, NextDigitHasDecPoint)
      NextDigitHasDecPoint = false
      Inc(curDigit)
  Next 
to:
Public Sub SetDisplayTestMode(pDispTestEnabled As Boolean)
    If pDispTestEnabled Then
        WriteReg(REG_DISP_TEST, 1)
    Else
        WriteReg(REG_DISP_TEST, 0)
    EndIf
Added line 433:
Changed lines 436-437 from:
* Name    : InitChip                                                      *
* Purpose : Initialize the MAX7219  CHIP                                   *
to:
* Name    : WriteDigit                                                    *
* Purpose : writes a value to position pDigitPos                          *
* param
  : pDigitPos = digit position from 0 to 7                        *
*          pValue    = value to write to at pDigitPos digit position      *
                        * values from 0 to 9 displays corresponding digit  *
                        * $A = displays "-" symbol                        *
                        * $B = displays "E" symbol                        *
                        * $C = displays "H" symbol                        *
                        * $D = displays "L" symbol                        *
                        * $E = displays "P" symbol                        *
                        * $F = blanks the digit                            *
                        Use the constants defined at top of this module    *
                          SYMB_DASH  As Byte = $A, ' displays "-" symbol  *
                          SYMB_E    As Byte = $B, ' displays "E" symbol  *
                          SYMB_H    As Byte = $C, ' displays "H" symbol  *
                          SYMB_L    As Byte = $D, ' displays "L" symbol  *
                          SYMB_P    As Byte = $E, ' displays "P" symbol  *
                          SYMB_BLANK As Byte = $F  ' blanks the digit      *
                                                                          *
*          pDecimalPointOn = True/False Switch On/Off decimal point led
  *
Changed lines 458-471 from:
Public Sub InitChip()
to:
Public Sub WriteDigit(pDigitPos As Byte, pValue As Byte, pDecimalPointOn As Boolean = false)
    pValue.Booleans(7) = pDecimalPointOn
    WriteReg(REG_DIGIT(pDigitPos), pValue)
End Sub

{
****************************************************************************
* Name    : BlankDisplay                                                  *
* Purpose : Writes blank to each digit of the display                      *
* Note    : this is **NOT** the same as DisplayOff() which puts the disp  *
*          in shutdown mode                                              * 
****************************************************************************
}
Public Sub BlankDisplay
()
Changed lines 473-480 from:
   For i = 0 To MAX7219_DISPLAY_COUNT-1
        SelectDisplay(i)
       SetNumberOfDigits(8)
        DisplayOn()
        SetDecodeMode(%11111111) // enables B-Decoding for all digits
        SetBrightness($A)          // can be up to 15. intensity 0 means display off
        WriteReg(REG_NO_OP, $FF)
        BlankDisplay(
)
to:
   For i = 0 To 7
      WriteDigit(i, $F, false)
Deleted line 475:
   SelectDisplay(0)
Changed lines 480-481 from:
* Name    : Initialize                                                    *
* Purpose : Initializes module and included modules                       *
to:
* Name    : WriteValue                                                    *
* Purpose : Writes a value to the display.                                 *
* Param  : pStr = string containing a formate value to display            *
*          Blanks and special symbols ("-", "H", "L", "E", "P", " ", "."  *
*          are handled  automatically by this routine
                    *
Changed lines 487-500 from:
Public Sub Initialize(

#If MAX7219_SPI_SOFTWARE
    SSPI.Initialize
    SSPI.SetClock(spiIdleHigh)
#Else
    SPI.SetAsMaster(spiOscDiv16)      
    SPI.SetClock(spiIdleHigh, spiRisingEdge)
   SPI.SetSample(spiSampleMiddle)
    EnableSPI()          
#EndIf   
    Output(CS)    
    High(CS)
    InitChip()
to:
Public Sub WriteValue(pStr As String)
 
  Dim i, value, curDigit As Byte
 
  Dim NextDigitHasDecPoint As Boolean
  NextDigitHasDecPoint = false
  curDigit = 0 'Length(pStr)-1
  For i = Length(pStr)-1 To 0 Step -1
    value = pStr(i)
      If value = 45 Then  ' "-"
         value = SYMB_DASH
      ElseIf value = 32 Then  ' " "
          value = SYMB_BLANK
      ElseIf value = 72 Then  ' "H"
          value = SYMB_H
      ElseIf value = 76 Then  ' "L"
          value = SYMB_L
      ElseIf value = 69 Then  ' "E"
          value = SYMB_E
      ElseIf value = 80 Then  ' "P"
          value = SYMB_P
      ElseIf value = 46 Then  ' "."
          NextDigitHasDecPoint = true
          Continue
      EndIf
      WriteDigit
(curDigit, value, NextDigitHasDecPoint)
      NextDigitHasDecPoint = false
      Inc(curDigit)
  Next 
Deleted lines 514-521:

Initialize()
=]

!!!Example Code
This program uses 2 MAX7219 modules, each handling 8 7Seg display module.

=code [=
Changed lines 516-551 from:
*************************************************************************
*  Name    : MAX7219.BAS                                                *
*
  Author  : Ahmed Lazreg  ([email protected])                        *
*
            http://www.pocketmt.com                                   *
*           http://www.microcodeproject.com                            *
*  Notice  : Copyright (c) 20015 Pocket MicroTechnics                  *
*         : All Rights Reserved                                        *
*  Date    : 01/01/2015                                                *
*  Version : 1.0                                                        *
*  Desc.  : Test program for MAX7219 module                            *
                                                                    *
*************************************************************************
}

Program Max7219_test

Device = 18F452
Clock = 20

Include "utils.bas"
Include "convert
.bas"

//#option MAX7219_SPI_SOFTWARE = true
#option MAX7219_DISP_COUNT = 2
Include "Max7219.bas"

Dim RED_LED
    As PORTB.1

Dim i, j As Word

Dim k As Float
Sub Init_MCU
()
    PORTA = %00000000
    TRISA = %11111100
    PORTB = %00000000
    TRISB = $00
    SetAllDigital
()
to:
****************************************************************************
*
Name    : InitChip                                                      *
* Purpose : Initialize the MAX7219
  CHIP                                  *
****************************************************************************
}

Public Sub InitChip()
    Dim i As Byte
    For i = 0 To MAX7219_DISPLAY_COUNT-1
        SelectDisplay(i)
        SetNumberOfDigits(8)
        DisplayOn()
        SetDecodeMode(%11111111) // enables B-Decoding for all digits
        SetBrightness($A)         // can be up to 15. intensity 0 means display off
 
      WriteReg(REG_NO_OP, $FF)
   
    BlankDisplay()
    Next
    SelectDisplay(0)
Changed lines 535-580 from:


Init_MCU()
High(RED_LED)

// main program loop
SelectDisplay(0)
SetDisplayTestMode(true)
DelayMS(300)
SetDisplayTestMode(false)
SelectDisplay(0)
WriteDigit(6, SYMB_E)
WriteDigit(7, SYMB_P)
DelayMS(1000)

SelectDisplay(0)
BlankDisplay()
WriteValue("HELP-. ")

SelectDisplay(1)
WriteValue("-41.73")
DelayMS(1000)

SelectDisplay(0)
BlankDisplay()
WriteValue("HELP    ")

SelectDisplay(1)
BlankDisplay()
WriteDigit(7, SYMB_L)

i = 0
j = 0
k = 0.0
While (true)
        Toggle(RED_LED)
        DelayMS(800)
        SelectDisplay(0)
        WriteValue(DecToStr(i))
        SelectDisplay(1)
        WriteValue(FloatToStr(k))
        i = i +1
        k = k + 0.2
End While

End Program
to:
{
****************************************************************************
* Name    : Initialize                                                    *
* Purpose : Initializes module and included modules                        *
****************************************************************************
}
Public Sub Initialize() 

#If MAX7219_SPI_SOFTWARE
    SSPI.Initialize
    SSPI.SetClock(spiIdleHigh)
#Else
    SPI.SetAsMaster(spiOscDiv16)       
    SPI.SetClock(spiIdleHigh, spiRisingEdge)
    SPI.SetSample(spiSampleMiddle)
    EnableSPI()           
#EndIf   
    Output(CS)   
    High(CS)
    InitChip()
End Sub

Initialize()
Added line 559:
Changed lines 33-34 from:
!!Single MCP23S17 chip module
to:
!!Single MAX7219 chip module connection
Changed lines 37-38 from:
http://www.pocketmt.com/images/mcp23s17.jpg
to:
http://www.pocketmt.com/images/max7219.png
Changed line 726 from:
=]
to:
=]
Added lines 1-726:
The MAX7219/MAX7221 are compact, serial input/output common-cathode display drivers that interface microprocessors (Ps) to 7-segment numeric LED displays of up to 8 digits, bar-graph displays, or 64 individual LEDs. Included on-chip are a BCD code-B decoder, multiplex scan circuitry, segment and digit drivers, and an 8x8 static RAM that stores each digit. Only one external resistor is required to set the segment current for all LEDs. The MAX7221 is compatible with SPI, QSPI, and MICROWIRE, and has slew-rate-limited segment drivers to reduce EMI.

A convenient 4-wire serial interface connects to all common Ps. Individual digits may be addressed and updated without rewriting the entire display. The MAX7219/MAX7221 also allow the user to select code-B decoding or no-decode for each digit.

The devices include a 150A low-power shutdown mode, analog and digital brightness control, a scan-limit register that allows the user to display from 1 to 8 digits, and a test mode that forces all LEDs on.


'''Main Features:'''

1- Handle one or multiple cascaded MAX72xx modules

2- Use Hardware or Software SPI to manage the MAX72xx module(s). Software SPI is usefull for little PICs that does not have SPI hardware module (like the little 18 pins 18F1320 mcu).

'''For any comment, or feedback (or bug report), please post to Swordfish Forum'''.

!!!VERY IMPORTANT NOTICE concerning Swordfish SPI module:
PS. I never got this module to work with official Swordfish hatdware SPI driver. I used instead a modified version of (hardware) SPI driver using some comments published by Steven on the forum (and sent to me by mail - Great thank Steven).
'''The modified version of the SPI module is also published at the END of this article.'''


!!!IMPORTANT Options


#option MAX7219_DISP_COUNT = nnValue    // where nnValue is the number of your cascaded modules. if not specified, defaults to 1 module

#option MAX7219_SPI_SOFTWARE = true // use Software SPI
#option MCPSPI_SOFTWARE = false    // Use Hardware SPI  (default to false)


#Option MCP_CS  = PORTC.1  // Chip Select Pin


!!Single MCP23S17 chip module

connection to hardware SPI is shown in following diagram (for software SPI you can use Swordfish Options to modify pins affectation).

http://www.pocketmt.com/images/mcp23s17.jpg

!!!Module Code
=code [=
{
*************************************************************************
*  Name    : MAX7219.BAS                                                *
*  Author  : Ahmed Lazreg  ([email protected])                        *
*            http://www.pocketmt.com                                    *
*            http://www.microcodeproject.com                            *
*  Notice  : Copyright (c) 20015 Pocket MicroTechnics                  *
*          : All Rights Reserved                                        *
*  Date    : 01/01/2015                                                *
*  Version : 1.0                                                        *
*  Modified:                                                            *
*  Notes  : This module handles Maxime Integrated(TM) MAX7219/MAX7221  *
*            Serially Interfaced, 8-Digit LED Display Drivers          *
*            It can be used via Hardware or Software SPI modules        *
*************************************************************************
}


Module MAX7219

Include "convert.bas"
Include "string.bas"

// Number of cascaded display modules
#if IsOption(MAX7219_DISP_COUNT) And Not (MAX7219_DISP_COUNT > 0)
  #error MAX7219_DISP_COUNT, "Invalid option, must be > 0"
#endif
#option MAX7219_DISP_COUNT = 1

Const MAX7219_DISPLAY_COUNT = MAX7219_DISP_COUNT
// hardware or software SPI...
#if IsOption(MAX7219_SPI_SOFTWARE) And Not (MAX7219_SPI_SOFTWARE in (true, false))
  #error MAX7219_SPI_SOFTWARE, "Invalid option, must be TRUE or FALSE."
#endif
#option MAX7219_SPI_SOFTWARE = false


#if MAX7219_SPI_SOFTWARE = true // use software SPI...
Include "sspi.bas"
#else // use hardware SPI...
Include "SPI.BAS"
#EndIf

#Option MAX7219_CS  = PORTC.1

// validate SCK pin...
#If IsOption(MAX7219_CS) And Not IsValidPortPin(MAX7219_CS)
  #Error MAX7219_CS, "Invalid option. MCP_CS must be a valid port pin."
#EndIf

Public Dim
  CS As [email protected]  // Chip select

' To be used with WriteDigit(...) subroutine
' for digits (0..9) just send the digit itself
' for non-digits, use codes below as pValue param in WriteDigit(...)
Public Const
    SYMB_DASH  As Byte = $A, ' displays "-" symbol
    SYMB_E    As Byte = $B, ' displays "E" symbol
    SYMB_H    As Byte = $C, ' displays "H" symbol
    SYMB_L    As Byte = $D, ' displays "L" symbol
    SYMB_P    As Byte = $E, ' displays "P" symbol
    SYMB_BLANK As Byte = $F  ' blanks the digit

' Internal registers of the MAX7219
Private Const
    REG_NO_OP      As Byte = $00,
    REG_DIGIT(8)    As Byte = ($01, $02, $03, $04, $05, $06, $07, $08),
    REG_DECODE_MODE As Byte = $09,
    REG_INTENSITY  As Byte = $0A,
    REG_SCAN_LIMIT  As Byte = $0B,
    REG_SHUTDOWN    As Byte = $0C,
    REG_DISP_TEST  As Byte = $0F

Private Dim fSelectedDisp As Byte

{
****************************************************************************
* Name    : SelectDisplay                                                  *
* Purpose : Selects active display                                        *
* param  : pDisplayIndex = display index.                                *
*            - First display module = 0                                  *
*            - pDisplayIndex must be < MAX7219_DISP_COUNT                *
****************************************************************************
}
Public Sub SelectDisplay(pDisplayIndex As Byte)
    If pDisplayIndex >= MAX7219_DISPLAY_COUNT Then
        pDisplayIndex = MAX7219_DISPLAY_COUNT
    EndIf
    fSelectedDisp = pDisplayIndex
End Sub

{
****************************************************************************
* Name    : GetSelectedDisplay()                                          *
* Purpose : returns actually selected Max7219 module                      *
****************************************************************************
}
Public Function GetSelectedDisplay() As Byte
    result = fSelectedDisp
End Function

' MAX7219 command format is
' [D15][D14][D13][D12] [D11 -  D8] [D7  -    D0]
' [ x ][ x ][ x ][ x ] [ REG_ADDR] [msb DATA lsb]

{
****************************************************************************
* Name    : WriteReg                                                      *
* Purpose : Writes pData byte to register address given by pRegAddress    *
****************************************************************************
}
Public Sub WriteReg(pRegAddress As Byte, pData As Byte)
    Dim i, count As Byte
    CS = 0  ' must be set here mainly because of Max7221
    count = MAX7219_DISPLAY_COUNT-fSelectedDisp-1
    For i = 1 To count
        WriteByte(REG_NO_OP)
        WriteByte($00)
    Next
    WriteByte(pRegAddress)
    WriteByte(pData)
    count = fSelectedDisp
    For i = 1 To count
        WriteByte(REG_NO_OP)
        WriteByte($00)
    Next
    CS = 1
End Sub

{
****************************************************************************
* Name    : SetDecodeMode                                                  *
* Purpose : Sets de Max7219 decode mode for each digit                    *
* param  : pDecodeMask = a 8 bit value. Setting  bit to 0/1              *
*          disables/enables the B-Decoding for concerned digit            *
                                                                          *
            When the code B decode mode is used, the decoder              *
            looks only at the lower nibble of the data in the digit        *
            registers (D3D0), disregarding bits D4D6. D7, which          *
            sets the decimal point (SEG DP), is independent of the        *
            decoder and is positive logic (D7 = 1 turns the decimal        *
            point on).                                                    *
            When no-decode is selected, data bits D7D0 correspond        *
            to the segment lines of the MAX7219/MAX7221.                  *
            Table 6 shows the one-to-one pairing of each data bit          *
            to the appropriate segment line.                              *
****************************************************************************
}
Public Inline Sub SetDecodeMode(pDecodeMask As Byte)
    WriteReg(REG_DECODE_MODE, pDecodeMask)
End Sub

{
****************************************************************************
* Name    : DisplayOn                                                      *
* Purpose : Enables the display                                            *
****************************************************************************
}
Public Inline Sub DisplayOn()
    WriteReg(REG_SHUTDOWN, $1)
End Sub

{
****************************************************************************
* Name    : DisplayOff                                                    *
* Purpose : Shuts down the display                                        *
****************************************************************************
}
Public Inline Sub DisplayOff()
    WriteReg(REG_SHUTDOWN, $0)
End Sub

{
****************************************************************************
* Name    : SetNumberOfDigits                                              *
* Purpose : Sets the number of digits availble in the display              *
* param  : pNumberOfDigits = value from  1 to 8                          *
*                                                                          *
*          WARNING:::: DANGEOUROUS !!!!!                                  *
*                                                                          *
*          If the scan-limit register is set for three digits or less,    *
*          individual digit drivers will dissipate excessive amounts      *
*          of power. Consequently, the value of the RSET resistor        *
*          must be adjusted according to the number of digits displayed,  *
*          to limit individual digit driver power dissipation.            *
*                                                                          *
* This function has been added only for debug purpose or                  *
* - when the Max7219 is used a LED driver (i.e Decode mode disabled)      *
* - when the Max7219 is cascaded with another Max7219 that is used to      *
*  less than 8 digits                                                    *
****************************************************************************
}
Public Sub SetNumberOfDigits(pNumberOfDigits As Byte)
    If pNumberOfDigits > 8 Then
        pNumberOfDigits = 8
    ElseIf pNumberOfDigits < 1 Then
        pNumberOfDigits = 1
    EndIf
    WriteReg(REG_SCAN_LIMIT, pNumberOfDigits-1)
End Sub

{
****************************************************************************
* Name    : SetBrightness                                                  *
* Purpose : Sets de Max7219 brightness                                    *
* param  : pIntensity = a 8 bit value between 0 to 15 (16 steps)          *
****************************************************************************
}
Public Inline Sub SetBrightness(pIntensity As Byte)
    WriteReg(REG_INTENSITY, (pIntensity And $F))
End Sub

{
****************************************************************************
* Name    : SetDisplayTestMode                                            *
* Purpose : Enables/Disables de Max7219 test mode                          *
* param  : pDispTestEnabled = True/False to Enable/Disable test mode      *
****************************************************************************
}
Public Sub SetDisplayTestMode(pDispTestEnabled As Boolean)
    If pDispTestEnabled Then
        WriteReg(REG_DISP_TEST, 1)
    Else
        WriteReg(REG_DISP_TEST, 0)
    EndIf
End Sub

{
****************************************************************************
* Name    : WriteDigit                                                    *
* Purpose : writes a value to position pDigitPos                          *
* param  : pDigitPos = digit position from 0 to 7                        *
*          pValue    = value to write to at pDigitPos digit position      *
                        * values from 0 to 9 displays corresponding digit  *
                        * $A = displays "-" symbol                        *
                        * $B = displays "E" symbol                        *
                        * $C = displays "H" symbol                        *
                        * $D = displays "L" symbol                        *
                        * $E = displays "P" symbol                        *
                        * $F = blanks the digit                            *
                        Use the constants defined at top of this module    *
                          SYMB_DASH  As Byte = $A, ' displays "-" symbol  *
                          SYMB_E    As Byte = $B, ' displays "E" symbol  *
                          SYMB_H    As Byte = $C, ' displays "H" symbol  *
                          SYMB_L    As Byte = $D, ' displays "L" symbol  *
                          SYMB_P    As Byte = $E, ' displays "P" symbol  *
                          SYMB_BLANK As Byte = $F  ' blanks the digit      *
                                                                          *
*          pDecimalPointOn = True/False Switch On/Off decimal point led  *
****************************************************************************
}
Public Sub WriteDigit(pDigitPos As Byte, pValue As Byte, pDecimalPointOn As Boolean = false)
    pValue.Booleans(7) = pDecimalPointOn
    WriteReg(REG_DIGIT(pDigitPos), pValue)
End Sub

{
****************************************************************************
* Name    : BlankDisplay                                                  *
* Purpose : Writes blank to each digit of the display                      *
* Note    : this is **NOT** the same as DisplayOff() which puts the disp  *
*          in shutdown mode                                              * 
****************************************************************************
}
Public Sub BlankDisplay()
    Dim i As Byte
    For i = 0 To 7
      WriteDigit(i, $F, false)
    Next
End Sub

{
****************************************************************************
* Name    : WriteValue                                                    *
* Purpose : Writes a value to the display.                                *
* Param  : pStr = string containing a formate value to display            *
*          Blanks and special symbols ("-", "H", "L", "E", "P", " ", "."  *
*          are handled  automatically by this routine                    *
****************************************************************************
}
Public Sub WriteValue(pStr As String)
  Dim i, value, curDigit As Byte
  Dim NextDigitHasDecPoint As Boolean
  NextDigitHasDecPoint = false
  curDigit = 0 'Length(pStr)-1
  For i = Length(pStr)-1 To 0 Step -1
    value = pStr(i)
      If value = 45 Then  ' "-"
          value = SYMB_DASH
      ElseIf value = 32 Then  ' " "
          value = SYMB_BLANK
      ElseIf value = 72 Then  ' "H"
          value = SYMB_H
      ElseIf value = 76 Then  ' "L"
          value = SYMB_L
      ElseIf value = 69 Then  ' "E"
          value = SYMB_E
      ElseIf value = 80 Then  ' "P"
          value = SYMB_P
      ElseIf value = 46 Then  ' "."
          NextDigitHasDecPoint = true
          Continue
      EndIf
      WriteDigit(curDigit, value, NextDigitHasDecPoint)
      NextDigitHasDecPoint = false
      Inc(curDigit)
  Next 
End Sub
{
****************************************************************************
* Name    : InitChip                                                      *
* Purpose : Initialize the MAX7219  CHIP                                  *
****************************************************************************
}
Public Sub InitChip()
    Dim i As Byte
    For i = 0 To MAX7219_DISPLAY_COUNT-1
        SelectDisplay(i)
        SetNumberOfDigits(8)
        DisplayOn()
        SetDecodeMode(%11111111) // enables B-Decoding for all digits
        SetBrightness($A)          // can be up to 15. intensity 0 means display off
        WriteReg(REG_NO_OP, $FF)
        BlankDisplay()
    Next
    SelectDisplay(0)
End Sub

{
****************************************************************************
* Name    : Initialize                                                    *
* Purpose : Initializes module and included modules                        *
****************************************************************************
}
Public Sub Initialize() 

#If MAX7219_SPI_SOFTWARE
    SSPI.Initialize
    SSPI.SetClock(spiIdleHigh)
#Else
    SPI.SetAsMaster(spiOscDiv16)       
    SPI.SetClock(spiIdleHigh, spiRisingEdge)
    SPI.SetSample(spiSampleMiddle)
    EnableSPI()           
#EndIf   
    Output(CS)   
    High(CS)
    InitChip()
End Sub

Initialize()
=]

!!!Example Code
This program uses 2 MAX7219 modules, each handling 8 7Seg display module.

=code [=
{
*************************************************************************
*  Name    : MAX7219.BAS                                                *
*  Author  : Ahmed Lazreg  ([email protected])                        *
*            http://www.pocketmt.com                                    *
*            http://www.microcodeproject.com                            *
*  Notice  : Copyright (c) 20015 Pocket MicroTechnics                  *
*          : All Rights Reserved                                        *
*  Date    : 01/01/2015                                                *
*  Version : 1.0                                                        *
*  Desc.  : Test program for MAX7219 module                            *
*                                                                      *
*************************************************************************
}

Program Max7219_test

Device = 18F452
Clock = 20

Include "utils.bas"
Include "convert.bas"

//#option MAX7219_SPI_SOFTWARE = true
#option MAX7219_DISP_COUNT = 2
Include "Max7219.bas"

Dim RED_LED    As PORTB.1

Dim i, j As Word
Dim k As Float
Sub Init_MCU()
    PORTA = %00000000
    TRISA = %11111100
    PORTB = %00000000
    TRISB = $00
    SetAllDigital()
End Sub



Init_MCU()
High(RED_LED)

// main program loop
SelectDisplay(0)
SetDisplayTestMode(true)
DelayMS(300)
SetDisplayTestMode(false)
SelectDisplay(0)
WriteDigit(6, SYMB_E)
WriteDigit(7, SYMB_P)
DelayMS(1000)

SelectDisplay(0)
BlankDisplay()
WriteValue("HELP-. ")

SelectDisplay(1)
WriteValue("-41.73")
DelayMS(1000)

SelectDisplay(0)
BlankDisplay()
WriteValue("HELP    ")

SelectDisplay(1)
BlankDisplay()
WriteDigit(7, SYMB_L)

i = 0
j = 0
k = 0.0
While (true)
        Toggle(RED_LED)
        DelayMS(800)
        SelectDisplay(0)
        WriteValue(DecToStr(i))
        SelectDisplay(1)
        WriteValue(FloatToStr(k))
        i = i +1
        k = k + 0.2
End While

End Program
=]


!!Modified Hardware SPI module

=code [=
{
****************************************************************************
*  Name    : SPI.BAS                                                      *
*  Author  : John Barrat                                                  *
*          : David John Barker                                            *
*  Notice  : Copyright (c) 2006 Mecanique                                  *
*          : All Rights Reserved                                          *
*  Date    : 26/05/2006                                                    *
*  Version : 1.1 Changed WriteByte() param to WREG for silicon workaround  *                                           
*          : 1.0 Release                                                  *
*          : ============================================================= *
*  Notes  : This post was made on the Swordfish forum by Steve B on      *
*          : April 8th 2007...                                            *
*          : I was having some trouble with the SPI module as well. I am  *
*          : using an 18F2620, Silicon A4, and was getting some            *
*          : inconsistent reads/writes, especially when doing a lot of    *
*          : TX/RX one after another. After looking at the errata, I      *
*          : changed the ReadByte and WriteByte routines as follows...    *
*          :                                                              *
*          : Public Function ReadByte() As SSPBuffer                      *
*          :    SSPIF = 0                                                  *
*          :    SSPBuffer = 0                                              *
*          :    Repeat                                                    *
*          :      ClrWDT                                                  *
*          :    Until SSPIF = 1                                            *
*          : End Function                                                  *
*          :                                                              *
*          : Public Sub WriteByte(pData As WREG)                          *
*          :    SSPIF = 0                                                  *
*          :    SSPBuffer = pData                                          *
*          :    Repeat                                                    *
*          :      ClrWDT                                                  *
*          :    Until SSPIF = 1                                            *
*          : End Sub                                                      *
*          :                                                              *
*          : Now they use the SSP Interrupt flag instead of the Buffer    *
*          : Full flag (SSPSTAT.0). I also added a subroutine to enable    *
*          : the SPI module                                                *
*          :                                                              *
*          : Public Sub EnableSPI()                                        *
*          :    Dim pDummy As Byte                                        *
*          :    Enabled = true                                            *
*          :    pDummy = SSPBuffer                                        *
*          :    SSPIF = 0                                                  *
*          : End Sub                                                      *
****************************************************************************
}
Module SPI

Include "system.bas"

// map registers to SSP(x)
#if _mssp = 0
  #error _device + " does not support MSSP"

// single SSP...
#elseif _mssp = 1
Dim
  SSPControl1 As SSPCON1,
  SSPStatus  As SSPSTAT,
  SSPBuffer  As SSPBUF,
  SCK As PORTC.3,
  SDI As PORTC.4,
  SDO As PORTC.5, 
  _SS As PORTA.5

// has more than one SSP module... 
#else
Dim                        // -> MSSP2
  SSPControl1 As SSP1CON1, //    as SSP2CON1
  SSPStatus  As SSP1STAT, //    as SSP2STAT
  SSPBuffer  As SSP1BUF,  //    as SSP2BUF
  SCK As PORTC.3,
  SDI As PORTC.4,
  SDO As PORTC.5, 
  _SS As PORTA.5
#endif

// SSPSTAT bitnames
Public Dim
  BF  As SSPStatus.0,            // buffer full (receive and transmit)   
  SMP As SSPStatus.7,            // read sample mode
  CKE As SSPStatus.6            // clock edge control

// SSPCON1 bitnames, master mode only...
Public Dim
  WCOL  As SSPControl1.7,        // write collision Detect
  SSPOV As SSPControl1.6,        // receive overflow
  SSPEN As SSPControl1.5,        // synchronous receive enable
  CKP  As SSPControl1.4,        // clock polarity
 
  // synchronous mode select bits, %00XX for master mode
  SSPM3 As SSPControl1.3,        // always zero
  SSPM2 As SSPControl1.2,        // slave Mode
  SSPM1 As SSPControl1.1,        // clock Mode (MSB)
  SSPM0 As SSPControl1.0        // clock Mode (LSB)

// interrupt flag
Public Dim
  SSPIF As PIR1.3


 
Public Const
  spiOscDiv4              = 0,  // master mode FOSC/4
  spiOscDiv16            = 1,  // master mode FOSC/16
  spiOscDiv64            = 2,  // master mode FOSC/64
  spiOscTimer2            = 3,  // master mode TMR2 provides clock
  spiSlaveSSEnabled      = 4,  // slave mode slave synch enabled
  spiSlaveSSDisabled      = 5,  // slave mode slave synch disabled
 
  // clock idle and edge settings  (SPI Mode compatible)
  spiRisingEdge          = $40, // data transmitted on rising edge of clock
  spiFallingEdge          = $00, // data transmitted on falling edge of clock
  spiIdleHigh            = $10, // idle state for clock is high
  spiIdleLow              = $00, // idle state for clock is low
 
  // RX data sampling settings  (SSPStatus.6 - SMP)
  spiSampleEnd            = $80, // input data sampled at end of data output time
  spiSampleMiddle        = $00  // input data sampled at middle of data output time

// local helper aliases... 
Dim
  FBufferIsFull As SSPStatus.Booleans(0)      // BF as boolean

// public aliases...
Public Dim
  Enabled As SSPControl1.Booleans(5),        // SSPEN as boolean
  Overflow As SSPControl1.Booleans(6),        // SSPOV as boolean
  WriteCollision As SSPControl1.Booleans(7)  // WCOL as boolean
{
****************************************************************************
* Name    : SetAsMaster                                                    *
* Purpose : Set SPI to master mode                                        *
*        : spiOscDiv4 (DEFAULT), spiOscDiv16, spiOscDiv64, spiOscTmr2    *
****************************************************************************
}
Public Sub SetAsMaster(pMode As Byte = spiOscDiv4)
  SSPControl1 = SSPControl1 And $F0
  SSPControl1 = SSPControl1 Or pMode
  Output(SDO)
  Output(SCK) 
End Sub
{
****************************************************************************
* Name    : SetAsSlave                                                    *
* Purpose : Set SPI to slave mode                                          *
*        : spiSlaveSSEnabled, spiSlaveSSDisabled (DEFAULT)                *
****************************************************************************
}
Public Sub SetAsSlave(pMode As Byte = spiSlaveSSDisabled)
  SSPControl1 = SSPControl1 And $F0
  SSPControl1 = SSPControl1 Or pMode
  Output(SDO)
  Input(SCK)
  Input(_SS) 
End Sub
{
****************************************************************************
* Name    : SetSample                                                      *
* Purpose : Sets when the SPI input data in sampled                        *
*        : spiSampleEnd, spiSampleMiddle. For slave mode, sample should  *
*        : always be spiSampleMiddle                                      *
****************************************************************************
}
Public Sub SetSample(pSample As Byte)
  SSPStatus = SSPStatus And $7F
  SSPStatus = SSPStatus Or pSample
End Sub
{
****************************************************************************
* Name    : SetClock                                                      *
* Purpose : Set SPI idle state and data transmission clock edge            *
*        : pIdle -> spiIdleHigh, spiIdleLow                              *
*        : pEdge -> spiRisingEdge, spiFallingEdge                        *
****************************************************************************
}
Public Sub SetClock(pIdle As Byte, pEdge As Byte)
  SSPControl1 = SSPControl1 And $EF
  SSPControl1 = SSPControl1 Or pIdle
  If pIdle = spiIdleHigh Then
      pEdge = Not pEdge And $BF
  EndIf
  SSPStatus = SSPStatus And $BF 
  SSPStatus = SSPStatus Or pEdge
End Sub
{
****************************************************************************
* Name    : ReadByte                                                      *
* Purpose : Read a single byte from the SPI bus                            *
****************************************************************************
}       
'Public Function ReadByte() As SSPBuffer
'  SSPBuffer = 0
'  Repeat
'      ClrWDT
'  Until FBufferIsFull
'End Function


Public Function ReadByte() As  SSPBuffer
      SSPIF = 0
      SSPBuffer = $FF
      Repeat
        ClrWDT
      Until SSPIF = 1
      ReadByte = SSPBuffer
End Function
   
Public Sub WriteByte(pData As Byte)
      SSPIF = 0
      SSPBuffer = pData
      Repeat
        ClrWDT
      Until SSPIF = 1
End Sub

{
****************************************************************************
* Name    : WriteByte                                                      *
* Purpose : Write a single byte to the SPI bus                            *
****************************************************************************
}       
'Public Sub WriteByte(pData As WREG)
'  SSPBuffer = pData
'  Repeat
'      ClrWDT   
'  Until FBufferIsFull
'End Sub

Public Sub EnableSPI()                                   
    Dim pDummy As Byte                                       
    Enabled = true                                           
    pDummy = SSPBuffer                                       
    SSPIF = 0                                                 
End Sub                                                   
=]