KM-AAA-31

Name: Mr. Ken Mathis
Company: ASC
Web Site:

;FILE NAME:MAX7219
;Date:June 16, 2004
;Programmer:Ken Mathis
;Purpose of this program is to control several seven segment displays using the MAX7219
;seven segment display driver IC. The seven segment displays are multiplexed with the
;7219 and are commone cathode type displays.


;This test code controls only 3 seven segment displays. The code can easily be expanded
;for the max7219 to control up to 8 seven segment displays while consuming only 3 SX
;output pins
;Where appropriate, explanations are provided to account for more than 3 seven segment displays

;This configuration uses the SX internal oscillator as the timimg for shifting data
;out is not critical
;-----[Assembler directives]---------------------------------------
ifdef __SASM
 DEVICE SX18L, STACKX, OPTIONX
 IRC_CAL IRC_FAST
 FREQ 4_000_000
else
 DEVICE SX18AC, OPTIONX
endif
DEVICE TURBO, OSC4MHZ
RESET START

;-----[Define variables and constants]------------------------------
org $07  ;$07 is first free variable space
Decode ds 2 ;assign 2 bytes of space for Decode - 7 & 8
ShtDn ds 2 ;assign 2 bytes of space for Shutdown - 9 & A
ScnLmt ds 2 ;assign 2 bytes of space for Scan Limit - B & C
Inten ds 2 ;assign 2 bytes of space for Intensity - D & E
bitcnt ds 1 ;assign 1 byte of space for bit counter - F

;dig0, dig1, & dig2 represent three 7 segment displays with a common cathode and
;dig0 is the least significant display
dig0 ds 2 ;assign 2 bytes of space for Digit 0 - 10 & 11
dig1 ds 2 ;assign 2 bytes of space for Digit 1 - 12 & 13
dig2 ds 2 ;assign 2 bytes of space for Digit 2 - 14 & 15
;To display more digits variable manes MUST be added here sequentially
;after dig2 for the code to properly work.


; !!! IF 8 SEVEN SEGMENT DISPLAYS ARE USED, there will be no more room
;for the word counter (wrdcnt) in bank one. To avoid switching banks in
;this circumstance, the upper or lower byte of any of the initialization
;words (Decode, ShtDn, ScnLmt, or Inten) can be reused/reloaded with
;the appropriate value after the initialization if finished. A comment
;will be shown where to reload Decode if needed

wrdcnt ds 1 ;assign 1 byte of space for word counter - 16


;----[Define symbolic pin names]---------------------------------------


data EQU rb.1 ;data pin connects to pin 1 of 7219
clock EQU rb.2 ;clock pin connects to 13 of 7219
load EQU rb.3 ;load pin connects to 12 of 7219

;-----[calls should be placed on first page between org $000 and org $100]--
org $000

;5uS delay - generated using the delay code generator at sxlist.com
del_5uS
 jmp $+1
 jmp $+1
 jmp $+1
 jmp $+1
 nop
 nop
 ret

;sub to shift out msbit of each byte into carry
rotate
 rl ind ;move msbit into carry
 jc high ;if carry is high jump to high
 clrb data ;if carry is low ensure data pin is low
 jmp $+2 ;jump 2 lines
high
 setb data ;make data pin high
 nop  ;no operation
 ret

;clock pulse generation to shift data out of SX into max 7219
shiftout
 call del_5uS ;5 uS set-up time
 setb clock ;make clock (rb.2) high
 call del_5uS ;5 uS hold time
 clrb clock ;make clock low
 ret  ;return

;-----[MAIN PROGRAM]------------------------------------------------------------
org $100

Start   ;reset point 

;-------[I/O port setting]------------------------------------------------------
 mode $0f ;set mode for port direction
 mov w,#$0
 mov !ra,w ; all ra ports output
 mov w,#$00
 mov !rb,w ;all rb ports output

;-------[prepare variables for initialization of max7219]-----------------------
;mov w,#$XX loads the w register with hex value
;mov NAME,w loads value of w into variable name
;Later in this program the initiazation is explained in detail
 mov w,#$09
 mov Decode,w
 mov Inten+1,w
 mov w,#$0f
 mov Decode+1,w
 mov w,#$10
 mov bitcnt,w
 mov w,#$0c
 mov shtdn,w
 mov w,#$01
 mov shtdn+1,w
 mov dig0,w
 mov w,#$0b
 mov scnlmt,w
 mov w,#$02
 mov scnlmt+1,w
 mov dig1,w
 mov w,#$0a
 mov inten,w
 mov w,#$03
 mov dig2,w
 mov w,#$04
 mov wrdcnt,w


;point to first register that will hold data to shift out which
;is Decode at address $07. NOTE that this is a SX18 and does not have an RC
;port. 
 mov w,#$07 
 mov fsr,w

;-------[The program currently causes display to load 4 to each digit. To test a
;different value, change four to any digit 0 to 9. Your actual program will load
;dig0+1, dig1+1 and dig2+1 with some dynamic data.
 mov w,#$04
 mov dig0+1,w
 mov dig1+1,w
 mov dig2+1,w


;------[MAX7219 Operation]----------------------------------------------------
;The 7219 must first be initialized. Initialization is done by sending serial
;data to the IC. Four 16 bit values sent will complete the initialization.

;To send a 16 bit value load is brought LOW, then each of 16 bits (msb 1st) is
;clocked into the IC, and load is then brought HIGH to complete the shifting
;of 16 bits into the device

;For each word sent to the IC, the most significant byte is the address and the
;lower byte sets the option for each particular function.
;For the descriptions that follow values will be shown as $Xx. The upper case x
;represents the upper nibble and the value is "don't care"

;DECODE MODE - Address $X9
;Options $X0 = No decoding
;  $X1 = Decode digit 0 (BCD)
;  $XF = Decode digits 0-3
;  $FF = Decode digits 0-7
;Sending $090F sets decode mode to enable digits 0-3 and unstucts that the least
;sig nibble is BCD

;SHUTDOWN MODE - Address $XC
;Options $X0 = Shutdown
;  $X1 = Normal Operation
;Sending $0C01 sets the IC for normal operation

;SCANLIMIT - Address $XB
;Options $Xx where the least significant nibble sets the number of digits
;  to enable. digit 0, x = 0. digits 0 & 1 x = 1. digits 0, 1, & 2 x = 2
;Sending $0B02 enbables digts 0, 1 & 2
;Sending $0B07 enables all 8 digits

;INTENSITY - Address $XA
;Options $00 = minimum intensity
;  $FF = maximum intensity
;  See MAX7219 data sheet for resistor selection and current


;----[set up SX controll pins]--------------------------------------------------------
 clrb data  ;make data pin low
 clrb clock  ;make clock pin low
 setb load  ;make load pin high
 call del_5uS  ;wait 5 uS

;----[Start of routine to send out first 16 bits]-------------------------------------
 clrb load  ;enable 7219 to start accepting serial data.
j1
 call rotate  ;call routine to move msbit into carry and set data pin
    ;high or low depending on state of bit carried out
 call shiftout ;call routine to shift data bit to 7219
 dec bitcnt  ;decrement bit counter
 cjne bitcnt,#8,j2 ;check if 8 bits have been sent out
 inc fsr  ;if 8 bits were sent, increment fsr to point to next
    ;register
 jmp $-8  ;move back up to call rotate
j2
 cja bitcnt,#0,j1 ;check of bit counter is at zero (16 bits shifted out?)
 setb load  ;if 16 bits shifted out, load them into the 7219
 dec wrdcnt  ;check if the 4 initialization words shifted out
 cja wrdcnt,#0,j3 ;if word counter is above 0, jump to j3
 jmp $+5  ;if the 4 initialization words shifted out jump down 5 lines
j3 
 mov w,#$10  ;reload bit counter with 16
 mov bitcnt,w ;reload bit counter with 16
 inc fsr  ;increment fsr to point to the next register
 jmp $-$18  ;jump up to the "clrb load" instruction to start another
    ;sequence of shifting out 16 more bits


;-----[shift actual data into max7219]---------
;Data is sent to the 7219 in the same manner as the initialization described above.
;load is brought LOW, 16 bits clocked into device and load is brought HIGH to complete
;the loading of one digit.

;For each digit, the upper byte of 16 bits is the address of the digit and the lower
;byte is the value sent to the 7 segment. This value is either BCD or the "word" to control
;each of the 8 segments (decimal point). Remember that DECODE MODE determines how to
;use the lower byte

;For digit 0 the address is $01
; digit 1 the address is $02
; digit 2 the address is $03

;If decode mode was selected sending the 16 bit value of $0207 will tell the IC that
;digit number 1 gets a value of 7


 mov w,#$10
 mov fsr,w  ;point to first address of digit 0 holding the most sig byte
 mov bitcnt,w ;load the bit counter with 16

;If using 8 seven segment displays as decribed above, comment out the next two lines
 mov w,#$03  ;since three digits are used in this example, wrdcnt is loaded w/3
 mov wrdcnt,w
;Use these next two lines if 8 seven segments are used.
; mov w,#$08
; mov Decode,w

;----[Start of routine to send out first 16 bits of TEST data]-------------------------------------
;The rest of this code is exactly the same as the initialization code, so no comments added here.
;see initialzation above for comments.
 clrb load  
j4
 call rotate
 call shiftout
 dec bitcnt
 cjne bitcnt,#8,j5
 inc fsr
 jmp $-8
j5
 cja bitcnt,#0,j4
 setb load
;If using 8 seven segment displays as decribed above, comment out the next two lines
 dec wrdcnt
 cja wrdcnt,#0,j6

;Use these next two lines
; dec Decode
; cja Decode,#0,j6

 jmp $+5
j6 
 mov w,#$10
 mov bitcnt,w
 inc fsr
 jmp $-$18

 setb load
 sleep

END

Interested: