MAX7221

Maxim Integrated(tm) MAX7219/MAX7221

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 150µA 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 of Swordfish MAX7219/MAX7221 module :

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

  1. option MAX7219_DISP_COUNT = nnValue // where nnValue is the number of your cascaded modules. if not specified, defaults to 1 module
  2. option MAX7219_SPI_SOFTWARE = true // use Software SPI
  3. option MCPSPI_SOFTWARE = false // Use Hardware SPI (default to false)
  4. Option MCP_CS = PORTC.1 // Chip Select Pin

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

??? diagram (coming soon)

Example Code for single MAX7219 module

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

{
*************************************************************************
*  Name    : MAX7219.BAS                                                *
*  Author  : Ahmed Lazreg  (ahmed.lazreg@pocketmt.com)                  *
*            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
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()
End Sub

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))   ' use FloatToStr(..) for floating point values
        i = i +1 
End While

End Program

Example Code two (02) cascaded MAX7219 modules

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

{
*************************************************************************
*  Name    : MAX7219.BAS                                                *
*  Author  : Ahmed Lazreg  (ahmed.lazreg@pocketmt.com)                  *
*            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

Module Code

{
*************************************************************************
*  Name    : MAX7219.BAS                                                *
*  Author  : Ahmed Lazreg  (ahmed.lazreg@pocketmt.com)                  *
*            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 MAX7219_CS.MAX7219_CS@   // 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 (D3–D0), disregarding bits D4–D6. 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 D7–D0 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()

Modified Hardware SPI module

{
****************************************************************************
*  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