please dont rip this site

SPI to MAX7221 LED Driver

by Marcel Birthelmer

The SPI LED Driver

The purpose of this project was to familiarize myself beyond the blinking-LED stage with programming.

I'm using a p16f648a to implement SPI communication with a Maxim IC Max7221 LED driver, which in turn drives 2 blocks of 2-digit 7-segment LED displays (for a total of 4 digits). The PIC also implements a (rather inefficient) decimal counter.

The SPI protocol

SPI is a rather simple bidirectional communication protocol. It was chosen because I already had the Max7221, and I also intend to use it on future projects. It consists of 4 pins on the client side and 3 pins on the host side which can be shared among all SPI clients, as well as a mechanism to drive the desired client's Chip Select (/CS) pin. The other pins are: SCLK (the clock), MISO (Master-In, Slave-Out), and MOSI (Master-out, Slave-In).

When sending a packet, the order of operations is as follows:

  1. /CS is asserted on the desired client chip
  2. The first bit is pushed out of MOSI (by the host)
  3. SCLK goes high
  4. The client reads the first bit
  5. The first bit is pushed out of MISO (by the client)
  6. SCLK goes low
  7. The host reads the first bit

... and so on for all 16 (in our case) bits. Note that other devices may have a different clock polarity, as well as requiring different timing relations on the first bit. Also note that /CS must be set high before the clock goes high again after the last bit, or data loss will occur (from the MAX7221 data sheet).

The Counter

The counter was simply designed for functionality, without regards to efficiency. On each counting cycle, the unit digit (CTR1) is increased by one. If it equals ten, the digit is reset to 0 and FSR is increased, and the cycle repeats. After 9999, the counter is reset back to 0. Again, this is by no means efficient, as the counter could be contained within 14 bits. However, I simply wanted a counter without working out hex->decimal conversion.


Delays are created simply by counting down from 255^n to 0, where 1<=n<=3 . Further revisions should probably use a variably scaled timer for the job.

The Circuit

{Ed: See the MAX7221 data sheet for connections to the LED 7-Segement displays} I'm using the p16f648a's internal 4MHz counter (occasionally switched to 48kHz mode for debugging). The pins on the pic are as follows: RA:2 is SPICLK, RB:0 is /CS, MOSI is RB:1, MISO is RB:2. Note that MISO isn't implemented since the MAX7221 doesn't really say anything.

The Code

	LIST P=16F648A, R=HEX
	include ""
OUT1 EQU 0x20
OUT2 EQU 0x21
IN1 EQU 0x22
IN2 EQU 0x23
TMP1 EQU 0x24
TMP2 EQU 0x25
CNT EQU 0x26
CTR1 EQU 0x28
CTR2 EQU 0x29
CTR3 EQU 0x30
CTR4 EQU 0x31


	org 0
	goto init
	org 0x10
init:	clrf PORTB ;clear port b
	movlw 0x04
	bsf STATUS, RP0
	movwf TRISB; all output except RB2
	bcf STATUS, RP0

	clrf PORTB
	bsf PORTB, CS

	movlw 0x09	; DECODE MODE : DIGITS 1-4
	movwf OUT1
	movlw 0x0F
	movwf OUT2

	call xfer16

	movlw 0x0A ; INADDRSITY : MAX
	movwf OUT1
	movlw 0x0F
	movwf OUT2

	call xfer16

	movlw 0x0B ; SCAN LIMIT : DIGITS 1 - 4
	movwf OUT1
	movlw 0x03
	movwf OUT2
	call xfer16
	movwf OUT1
	movlw 0x01
	movwf OUT2

	call xfer16

	clrf CTR1
	clrf CTR2
	clrf CTR3
	clrf CTR4

	movlw CTR1	; load starting address
	movwf FSR

bump:	incf INDF, 1 ; increase current digit
	movlw 0x0F ; restrict to last four bits
	andwf INDF, 0
	xorlw 0x0A ; check if equal to ten
	btfss STATUS, Z
	goto bump_done ; if not, done
	clrf INDF ; else, set to zero
	movf FSR, 0 ; check if this was the fourth digit
	xorlw CTR4
	btfsc STATUS, Z ; if so, we're done
	goto bump_done
	incf FSR, 1	; otherwise, go to next digit
	goto bump


	clrf ADDR
	movlw CTR1
	movwf FSR	; start at CTR1
pump:	incf ADDR, 1
	movf ADDR, 0	; send address
	movwf OUT1
	movf INDF, 0	; send digit value
	movwf OUT2

	call xfer16
	btfsc ADDR, 3	; finish if ADDR==4
	goto finish
	incf FSR, 1		; else send next
	goto pump

finish:	call l0
	goto mainloop

l0:	movlw 0xFF
	movwf 0x42
l0_loop:	decfsz 0x42,1
	goto l0_loop

l1:	movlw 0xFF
	movwf 0x41
l1_loop: call l0
	decfsz 0x41,1
	goto l1_loop

l2:	movlw 0xFF
	movwf 0x40
l2_loop:	call l1
	decfsz 0x40,1
	goto l2_loop

xfer16:	bcf PORTB, CS	; assert /CS
	movf OUT1, 0		
	call xfer8			; send first byte
	movwf IN1
	movf OUT2, 0
	call xfer8			; send second byte
	movwf IN2
	bsf PORTB, CS		; de-assert /CS
	call l0				; wait

xfer8:	movwf TMP1
	movlw 0x8
	movwf CNT

	rlf TMP1, 1 ;rotate MSB of TMP1 into C
	bcf PORTB, MOSI	;clear output bit
	btfsc STATUS, C ;if rotated-out bit was high,
	bsf PORTB, MOSI ;output high bit
	nop				;keep time constant
	bsf PORTA, SPICLK	;bring clock high

	nop	;8x nop to make clock symmetric

	; this would implement MISO, except that we don't need it.
;	bcf STATUS, C		;clear C
;	btfsc PORTB, MISO	;test MISO bit
;	bsf STATUS, C		;set C if MISO bit set
;	nop					;keep time constant
;	rlf TMP2, 1			;rotate carry into TMP2
	decfsz CNT, 1
	goto xfer1
	movf TMP2,0			; 'return' TMP2

file: /Techref/microchip/spi-max7221-mb.htm, 5KB, , updated: 2007/7/31 14:03, local time: 2024/6/16 01:56,

 ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions?
Please DO link to this page! Digg it! / MAKE!

<A HREF=""> SPI to MAX7221 LED Driver by Marcel Birthelmer</A>

After you find an appropriate page, you are invited to your to this massmind site! (posts will be visible only to you before review) Just type a nice message (short messages are blocked as spam) in the box and press the Post button. (HTML welcomed, but not the <A tag: Instead, use the link box to link to another page. A tutorial is available Members can login to post directly, become page editors, and be credited for their posts.

Link? Put it here: 
if you want a response, please enter your email address: 
Attn spammers: All posts are reviewed before being made visible to anyone other than the poster.
Did you find what you needed?


Welcome to!


Welcome to!