Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

SPI Code Help

Status
Not open for further replies.

rmain1972

Member
Hello all,

I'm working on interfacing a 2 Digit CC display to a MC14489B using SPI and a 16F818 chip. The chip hangs in a loop because a test LED never blinks, but stays on steady. When the communication with the MC14489B is commented out, ie init and display routine, the test LED blinks.

I have verified wire connections using a multi-meter checking for continuity. All the pins check out. As below

16F818 MC14489B
7 SDI -- DATA OUT -- 18
8 SDO -- DATA IN -- 12
10 SCK -- CLOCK -- 11
11 RB5 -- ENABLE -- 10

I suspect that it may be code that is the issue. I took the code from a power point available on the microchip site. Below is the code that I am using. Understand that I'm only trying to initialize the chip first with one byte of data, then I will send the 3 display bytes.

Any help or ideas would be helpful. What sucks is that I had it working in the past (2006) with a frequency counter on a different breadboard, but a crashed hard drive and no backup prevents me from looking at what I did in the past.

Thanks.

Code:
	list      p=16f818           ; list directive to define processor
	#include <p16F818.inc>        ; processor specific variable definitions

	errorlevel  -302              ; suppress message 302 from list file

	__CONFIG   _CP_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _CCP1_RB2 & _DEBUG_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_IO 

; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file.
; See data sheet for additional information on configuration word settings.

;***** VARIABLE DEFINITIONS
w_temp        EQU     0x7E        ; variable used for context saving 
status_temp   EQU     0x7F        ; variable used for context saving

	cblock 0x20					  ; general purpose ram starts as 0x20 on the 16F818
	d1
	d2
	d3
	outbyte1
	outbyte2
	outbyte3
	endc




;**********************************************************************
	ORG     0x000             ; processor reset vector
	goto    main              ; go to beginning of program
	

	ORG     0x004             ; interrupt vector location
	movwf   w_temp            ; save off current W register contents
	movf	STATUS,w          ; move status register into W register
	movwf	status_temp       ; save off contents of STATUS register


; isr code can go here or be located as a call subroutine elsewhere
	

	movf    status_temp,w     ; retrieve copy of STATUS register
	movwf	STATUS            ; restore pre-isr STATUS register contents
	swapf   w_temp,f
	swapf   w_temp,w          ; restore pre-isr W register contents
	retfie                    ; return from interrupt


main

; remaining code goes here

; set internal clock speed
	banksel OSCCON
	movlw   b'01110000'                     ;8MHz internal RC oscilator
		   ;  x111xxxx
  	
	movwf   OSCCON                          ;set the new clock speed
	nop										
	nop
	nop
	nop

;Setup SPI Mode
	banksel SSPCON			; SPI Configuration
	movlw b'0010000'		; bit 7 Write Collision Detect bit 				- 0
	movwf SSPCON			; bit 6 Recieve Overflow bit					- 0
							; bit 5 Synchronous Serial Port Enable 			- 1		Turn On SPI Mode, Enable and configure SCK, SDO, and SDI
							; bit 4 Clock Polarity bit						- 0		TX on rising edge, RX on falling edge, IDLE state for clock is a low level
							; bit 3-0 Synchronous Serial Port Mode Select	- 0000	SPI Master Mode, clock OSC/4
							; Must also configure TRISB bits as appropriate for SCK, SDO, and SDI
						
; Setup Port B
	banksel TRISB			; TRISB is in Bank 1       
							
	movlw b'11001010'		;            Intended Function
	movwf TRISB				; bit 7 (RB7) Available															- 1 (Default Input)
							; bit 6 (RB6) Available															- 1 (Default Input)
							; bit 5 (RB5) Used to Enable MC14489B Display Driver							- 0 (Output)
							; bit 4 (RB4) Overriden by SSP Module as SCK									- 0 (Output)
							; bit 3 (RB3) Available															- 1 (Default Input)
							; bit 2 (RB2) Overriden by SSP Module as SDO									- 0 (Output)
							; bit 1 (RB1) Overriden by SSP Module as SDI 									- 1 (Input)
							; bit 0 (RB0) to output so we can source a LED to indicate on condition			- 0 (Output)
							
							
							

							

							; OPTION Register is in Bank 1
	;bsf OPTION, 7			; Disable PORTB weak pull ups

; Initilize MC14489B Display Driver
	call InitMC14489B

; Test MC14489B
; Display 1, 2, 3 on 3 Digit Display
							; Digit 2	Digit 1
;	movlw b'00100001'		; 0010 = 2, 0001 = 1
;	movwf outbyte1			
							; Digit 4	Digit 3
;	movlw b'00000011'		; 0000 = 0, 0011 = 3
;	movwf outbyte2			
							; D23 = High, Brighten LEDs
							; D22-D20 = Low, Activate h in all banks
;	movlw b'10000000'		; Digit 5 = 0000
;	movwf outbyte3

;	call SendDisplayInfo	; Transmit 3 bytes of data to MC14489B		

	banksel PORTB			; Bank 0

Loop
	bcf PORTB, 0			; Turn off LED
	call Delay				; Delay 1 second
	bsf PORTB, 0			; Turn on LED
	call Delay				; Delay 1 second
	
	goto Loop
	

; Delay Code
; Delay = 1 seconds
; Clock frequency = 8 MHz

; Actual delay = 1 seconds = 2000000 cycles
; Error = 0 %

Delay
			;1999996 cycles
	movlw	0x11
	movwf	d1
	movlw	0x5D
	movwf	d2
	movlw	0x05
	movwf	d3
Delay_0
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	$+2
	decfsz	d3, f
	goto	Delay_0

			;4 cycles (including call)
	return

; Init MC14489B Display Driver
InitMC14489B
	banksel PORTB
	bsf PORTB, 5				; Initilize ENABLE to High
	
	movlw b'00000001'			; C7 = L, No Decode
								; C6 = L, No Decode
								; C5 = L, Hex Decode Digit 5
								; C4 = L, Hex Decode Digit 4
								; C3 = L, Hex Decode Digit 3
								; C2 = L, Hex Decode Digit 2
								; C1 = L, Hex Decode Digit 1
								; C0 = H, Normal Mode
	movwf outbyte1				
	call SendByte				; Send the configuration byte to the MC14489B
	return

SendByte
	banksel PORTB				; PORTB and SSPBUF are in the same bank
	bcf PORTB, 5				; Set ENABLE to LOW to signal that we are sending data
	movf outbyte1, w
	movwf SSPBUF				; Transmit byte
	banksel SSPSTAT
SBWait1
	btfss SSPSTAT, BF			; Data transfer complete?
	goto SBWait1
	banksel PORTB
	bsf PORTB, 5				; Set Enable to HIGH to signal that we are done sending data
	return

SendDisplayInfo
	banksel PORTB				; PORTB and SSPBUF are in the same bank
	bcf PORTB, 5				; Set ENABLE to LOW to signal that we are sending data
	movf outbyte1, w
	movwf SSPBUF				; Send Byte 1
	banksel SSPSTAT				; Data transfer complete?
SDWait1
	btfss SSPSTAT, BF
	goto SDWait1
	
	banksel outbyte2
	movf outbyte2, w
	movwf SSPBUF				; Send Byte 2
	banksel SSPSTAT
SDWait2
	btfss SSPSTAT, BF
	goto SDWait2

	banksel outbyte3
	movf outbyte3, w			
	movwf SSPBUF				; Send Byte 3
	banksel SSPSTAT
SDWait3
	btfss SSPSTAT, BF
	goto SDWait3

	bsf PORTB, 5				; Set ENABLE to HIGH to singal that we are done sending data
	return
 
You need to read SSPBUF after the transfer is complete or you will get overflow errors. So try,
Code:
SendByte
	banksel PORTB				; PORTB and SSPBUF are in the same bank
	bcf PORTB, 5				; Set ENABLE to LOW to signal that we are sending data
	movf outbyte1, w
	movwf SSPBUF				; Transmit byte
	banksel SSPSTAT
SBWait1
	btfss SSPSTAT, BF			; Data transfer complete?
	goto SBWait1
	banksel PORTB
	bsf PORTB, 5				; Set Enable to HIGH to signal that we are done sending data
	[COLOR="red"]movfw SSPBUF[/COLOR] 
	return

Mike.
 
I added the code, but it still doesn't work. I even tried another MC14489B, but it does the same thing. I'm now going to rebuild the circuit on another breadboard (where it worked in the past). The only difference between the frequency counter and this one is that I'm running at 8 Mhz vs 4 Mhz. I'm also going to try in circuit debugging.

Thanks for the help, Mike.
 
I just checked the datasheet for the MC14489B, and loaded up the datasheet for the PIC16F818 (I've used it many times).
If you check the SPI modules config registers SSPCON, and SSPSTAT it'll show you the clock polarity. The timing diagram on the MC14489B's datasheet is a bit crap but it shows it reads in data on the RISING edge of every clock. It also writes data on its Dout pin on the falling clock (should you need it). So, both devices should output data on the FALLING edge of every clock. And both devices read data in on the RISING edge.

The long version:
Although you have written to the SSPCON register to turn on the module, with clk/4, you haven't written to the SSPSTAT register which also plays a part in when data is set up, falling, or rising edge of the SCLK. You have CKP=0, from SSPCON, and CKE=0 (default value if you don't write to it). Check the datasheet and you'll see the timing diagrams for combinations of CKP, and CKE. With 0,0 as their respective values, you are setting up data on the rising edge, with a idle clock of LOW. This should be changed so you setup data on the falling edge (the first data bit appears on the output pin as soon as you write to SSPBUF).

The short version:
Replace your SPI setup routine with this:
Code:
;
Setup SPI Mode
	banksel SSPCON
	movlw b'00100000'	; you only used 7 bits here, heh, doesn't matter
	movwf SSPCON
	banksel SSPSTAT
	movlw b'01000000'
	movwf SSPSTAT

That should work nicely. I suspect it worked before with incorrect data phasing because of slight timing delays in both the SPI module and the MC14489B, which were greater with a slower clock. Sometimes they can work when you don't set up the data correctly, (with longer wires, cable capacitance, and other annoying analogue properties of data transmission) but it's unreliable and generally works at slower speed.

Let me know if it works!
 
I'll give it a try. Thanks for your help.
 
I've run your code in ISIS and it hangs at the "btfss SSPSTAT, BF"

One thing that I've noticed in Hi-Tec's and microchips C18's implementation of SPI is that on a transmit the BF isn't available, you should poll the TXIF to see if the buffer is empty.
I don't have this chips model so I can test any further.

Ian
 
Just re-read your post. Although I'm sure my code snippet will improve comms with the the chip, Pommie has the right idea there. Every SPI routine I've written reads the SSPBUF after the transfer, whether its reading in, or the SDI pin is connected to anything or not. I even have annotation in some code which says 'must read SSPBUF after transfer, or SPI module hangs'. So I guess thats the answer, at least for getting the InitMC1489B routine to function correctly.
 
Working

It still wasn't working with the suggestions above, so for grins I changed clock polarity (bit 4 SSPCON) to 1. ;) It is working now, thanks for all your help.

Ralph
 
Not Working. :( I have been trying to troubleshoot because when I switched the CKP bit to 1, 00 came up on the two digit display. I then sent the 24 bits to update the display and blank... I have tried mode 0,0 and 1,1 but no success the 2 digit display remains blank, but my program does not freeze because the LED is blinking. I have rewritten the code in MikroC using the SPI1_Init routine (default) and it does the same thing. I'm going to read the incoming data and see if it is the same as what I am sending. If it is, then I'm stummped. Another avenue is that I have read the HEX file from the frequency counter that I built a long time ago (where it was talking to the MC14489). Does anyone know of a program to convert a HEX file to assembly? I found PIC-disassembler. I'll try it when I get home.
 
Last edited:
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top