;***************************************************************************
;                                                                     
;	NSC ADC12130 Software Interface on PIC 16F84  V1.02
;	===================================================
;
;	written by Peter Luethi, 31.7.1999, Dietikon, Switzerland
;	http://www.electronic-engineering.ch
;	last update: 19.04.2004
;
;	V1.02:	Added LCDcflag (LCD command/data flag) to comply with
;		latest LCD modules.
;		(19.04.2004)
;
;	V1.01:	Updated to latest revision of m_lcd_bf.asm
;		(31.12.2000)
;
;	This code and accompanying files may be distributed freely and
;	modified, provided this header with my name and this notice remain
;	intact. Ownership rights remain with me.
;	You may not sell this software without my approval.
;
;	This software comes with no guarantee or warranty except for my
;	good intentions. By using this code you agree to indemnify me from
;	any liability that might arise from its use.
;
;	
;	SPECIFICATIONS:
;	===============
;	Processor:		Microchip PIC 16F84
;	Clock:			4.00 MHz XT
;	Throughput:		1 MIPS
;	Required Hardware:	NSC ADC12130, dot matrix LCD display
;
;
;	DESCRIPTION:
;	============
;	This is a communication test routine between the PIC16F84 and 
;	the NSC ADC12130 12 bit A/D Converter based on the software-
;	implemented SSP (Synchronous Serial Port) interface.
;	The following features are implemented:
;	- Setup of SSP communication and control lines to A/D converter
;	- Auto Calibration and Mode Configuration of A/D converter
;	- Status Read of A/D configuration
;	- Readout of A/D value and display on LCD Display.
;
;	Output format:	16 bit unsigned, MSB first, CH0 single-ended :
;			0 0 0 0 MSB <12 bit data> LSB
;                                                                     
;***************************************************************************

;***** COMPILATION MESSAGES & WARNINGS *****

	ERRORLEVEL -207 	; Found label after column 1.
	ERRORLEVEL -302 	; Register in operand not in bank 0.

;***** PROCESSOR DECLARATION & CONFIGURATION *****

	PROCESSOR 16F84
	#include "p16F84.inc"
	
	; embed Configuration Data within .asm File.
	__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

;***** MEMORY STRUCTURE *****

	ORG	0x00		; processor reset vector
  	goto    MAIN

	ORG     0x04		; interrupt vector location
	goto	MAIN		; no Interrupt Service Routine

;***** PORT DECLARATION *****

	LCDtris	equ	TRISB
	LCDport	equ	PORTB

	#define	CS	PORTA,0	; chip select, active low
	#define	CONV	PORTA,1	; do conversion, active low
	#define	DO	PORTA,2	; serial data output
	#define	SCK	PORTA,3	; serial clock, idle state low
	#define	DI	PORTA,4	; serial data input

;***** CONSTANT DECLARATION *****

	CONSTANT BASE = 0x0C	; Base address of user file registers

   ;*** CONFIGURATION COMMANDS of NSC ADC12130 ***
	CONSTANT AutoCal    = b'00100000'
	CONSTANT AutoZero   = b'00100100'
	CONSTANT PowerUp    = b'00101000'
	CONSTANT PowerDown  = b'00101100'
	CONSTANT StatusRead = b'00110000'
	CONSTANT Unsigned   = b'00110100'
	CONSTANT Signed     = b'10110100'
	CONSTANT AT6        = b'00111000'
	CONSTANT AT10       = b'01111000'
	CONSTANT AT18       = b'10111000'
	CONSTANT AT34       = b'11111000'
	CONSTANT DummyCmd   = b'00000000'

   ;*** CH0 : channel 0, se : single-ended, format, first bit ***
	CONSTANT CH0se12MSB = b'10000000'
	CONSTANT CH0se16MSB = b'10000100'
	CONSTANT CH0se12LSB = b'10010000'
	CONSTANT CH0se16LSB = b'10010100'

   ;*** CH1 : channel 1, se : single-ended, format, first bit ***
	CONSTANT CH1se12MSB = b'11000000'
	CONSTANT CH1se16MSB = b'11000100'
	CONSTANT CH1se12LSB = b'11010000'
	CONSTANT CH1se16LSB = b'11010100'

   ;*** CH0 : CH0 vs CH1, df : differential mode, format, first bit ***
	CONSTANT CH0df12MSB = b'00000000'
	CONSTANT CH0df16MSB = b'00010000'
	CONSTANT CH0df12LSB = b'00010000'
	CONSTANT CH0df16LSB = b'00010100'

;***** REGISTER DECLARATION *****

	FLAGreg	equ	BASE+d'6'
	#define LCDbusy FLAGreg,0x00	; LCD busy flag
	#define	LCDcflag FLAGreg,0x01	; LCD command/data flag

	b16_cnt equ	BASE+d'7' ; counter for 16 bit binary output
	AD_cnt	set	BASE+d'8' ; counter for A/D readout
	HI	equ	BASE+d'9'
	LO	equ	BASE+d'10'
	HI_TEMP	set	BASE+d'11'
	LO_TEMP	set	BASE+d'12'
	SSPSR	equ	BASE+d'13' ; SSP Shift Register

;***** INCLUDE FILES *****

	#include "..\m_bank.asm"
	#include "..\m_wait.asm"
	#include "..\m_lcd_bf.asm"
	#include "..\m_lcdb16.asm"

;***** MACROS *****

ADinit	macro
	BANK1
	movlw	b'11110000'	; set A/D control lines I/O direction
	movwf	TRISA
	BANK0

	movlw	b'00000011'	; set A/D control lines :
	movwf	PORTA		; disable chip select & conversion,
	endm			; SCK low

ADenable macro
	movlw	b'11111100'	; select chip & enable conversion
	andwf	PORTA,1
	endm

ADdisable macro
	movlw	b'00000011'	; deselect chip & disable conversion
	iorwf	PORTA,1
	endm

ADcmd	macro	ADcommand
	movlw	ADcommand
	call	AD_cmd
	endm

;***** SUBROUTINES *****

AD_cmd	movwf	SSPSR		; call with command in w
	movlw	d'8'
	movwf	AD_cnt
ad_loop	
	;*** TRANSMISSION : MSB out on pin DO ***
	btfss	SSPSR,7		; check MSB, skip if set
	bcf	DO
	btfsc	SSPSR,7		; check MSB, skip if cleared
	bsf	DO
	; btfss/btfsc used due to illegal consecutive write cycles
	; on output pins and to prevent unnecessary spikes:
	; only one write cycle is performed

	;*** rotate SSPSR left, because bit 7 clocked out ***
	rlf	SSPSR,1
	nop			; settle time for transmission

	;*** RECEPTION on rising edge of serial clock ***
	bsf	SCK		; clock high
	nop			; settle time for clock high
	bcf	SSPSR,0		; fetch data applied on DI
	btfsc	DI
	bsf	SSPSR,0
	
	;*** TRANSMISSION on falling edge of serial clock ***
	bcf	SCK		; clock low

	decfsz	AD_cnt,1
	goto	ad_loop
	RETURN


;************** MAIN **************

MAIN	LCDinit
	ADinit

	LCDchar	'N'
	LCDchar	'S'
	LCDchar	'C'
	LCDchar	' '
	LCDchar	'A'
	LCDchar	'D'
	LCDchar	'C'
	LCDchar	'1'
	LCDchar	'2'
	LCDchar	'1'
	LCDchar	'3'
	LCDchar	'0'
	LCDchar	' '
	LCDchar	'C'
	LCDchar	'I'
	LCDchar	'N'

	LCDline	2

	LCDchar	'T'
	LCDchar	'e'
	LCDchar	's'
	LCDchar	't'
	LCDchar	'-'
	LCDchar	'I'
	LCDchar	'n'
	LCDchar	't'
	LCDchar	'e'
	LCDchar	'r'
	LCDchar	'f'
	LCDchar	'a'
	LCDchar	'c'
	LCDchar	'e'

	WAITX	d'16',d'7'


;*** Display Default Configuration of the A/D: Status Read ***

	ADenable
	ADcmd	StatusRead
	ADdisable
	
	LCDcmd	LCDCLR
	LCDchar	'S'
	LCDchar	't'
	LCDchar	'a'
	LCDchar	't'
	LCDchar	'u'
	LCDchar	's'

;*** Set A/D output format to unsigned ***

	ADenable
	ADcmd	Unsigned
	movfw	SSPSR	
	movwf	HI		; get upper 8 bits of status data
	; get remaining bit of status data :
	bsf	SCK		; clock high
	nop			; settle time for clock high
	clrf	LO
	btfsc	DI
	bsf	LO,7		; store remaining status bit
	bcf	SCK		; clock low
	ADdisable
	
	LCD_DDAdr 0x07		; display status data: 9 bits (!)
	LCDbin_16		; default: 13 bit, MSB first, signed

	WAITX	d'25',d'7'

;*** Set Aquisition Time to 34 CCLK Cycles ***

	ADenable
	ADcmd	AT34		; wait at least 34 tck
	ADdisable		; = 0.0085 ms  @  4 MHz
	WAIT	0x01

;*** Auto-Calibration of A/D ***

	ADenable
	ADcmd	AutoCal		; wait at least 4944 tck
	ADdisable		; = 1.232 ms  @  4 MHz
	WAIT	0x03

;*** Auto-Zero of A/D ***

	ADenable
	ADcmd	AutoZero	; wait at least 76 tck
	ADdisable		; = 0.019 ms  @  4 MHz
	WAIT	0x01

;*** Display Current Configuration of the A/D: Status Read ***


	ADenable
	ADcmd	StatusRead	; Note: the returned bit length
	ADdisable		; corresponds to the preceeding command
	WAIT	0x01

	ADenable
	;*****************
	ADcmd	CH0se16MSB	; CH0, single-ended, 16 bit, MSB first
	;ADcmd	CH1se16MSB	; CH1, single-ended, 16 bit, MSB first
	;*****************
	movfw	SSPSR	
	movwf	HI		; get upper 8 bits of status data
	; get remaining bit of status data :
	bsf	SCK		; clock high
	nop			; settle time for clock high
	clrf	LO
	btfsc	DI
	bsf	LO,7		; store remaining status bit
	bcf	SCK		; clock low
	ADdisable
	
	LCD_DDAdr 0x07		; display status data: 9 bits (!)
	LCDbin_16		; now: 16 bit, MSB first, unsigned


;*** A/D Value Readout ***

Loop	; wait at least Tacq + Tconv = (34 + 44) Tclk
	;                            = 78 Tclk = 20 us @ 4 MHz
	WAIT	0x01		; wait 1 ms

	ADenable
	;*****************
	ADcmd	CH0se16MSB	; CH0, single-ended, 16 bit, MSB first
	;ADcmd	CH1se16MSB	; CH1, single-ended, 16 bit, MSB first
	;*****************
	movfw	SSPSR	
	movwf	HI
	bsf	CONV		; disable conversion (for safety reasons)
	ADcmd	DummyCmd
	movfw	SSPSR	
	movwf	LO
	ADdisable

	LCD_DDAdr 0x40		; display A/D data
	LCDbin_16

	goto	Loop		; re-entry
	END

