Electronic Circuits and Projects Forum



languer

RS-232 SPI CONTROLLER – part 3.1

by languer , 11th February 2012 at 06:21 AM (1855 Views)
I’ve decided to add a timeout to both the bidirectional routine and the unidirectional routine; and then wrap this up. This project originated from a need to control two SPI devices from ADI. The single unidirectional controller presented before was based on that.

The bidirectional controller was based on a need to control a proprietary SPI interface; this sort of died away, so no good reason to keep pushing it. The interface work for this is done and tested; but I have no real use at the moment. The unidirectional controller on the other hand, I have plenty of use for.

Let’s do a brief flow diagram a few of the things we did previously using Oshonsoft Basic just for the sake of sanity.
> Open UART for 19,200bps – there is no particular reason for this speed; but you certainly wouldn’t want it to make it slower (faster is better ).
> Initialize signals to inputs and outputs – set outputs to desired states.
> Set global flag to indicate when a complete packet has been received (flag_rxcomplete = _false).
> Go into loop waiting to execute main code once a complete packet has been received.
> Inside UART interrupt routine
>> monitor for start of packet (STX),
>> indicate when it is received (flag_rxinprogress),
>> store data as received until packet length is reached (If packet_len = data_buffer_cnt),
>> if all data is received properly indicate the complete packet was received (flag_rxcomplete = _true),
>> if there was a hiccup on the received data, restart the process (flag_rxcomplete = _false).
> Once a complete packet is received,
>> set SPI mode (spi_mode = data_buffer(0)),
>> initialize SPI port (Call spi_init(spi_mode)),
>> send data (Call spi_send(spi_mode, data)),
>> for the bidirectional case
>>> receive data (data = spi_receive(spi_mode)),
>>> send data through UART (Hserout data).
>> restart the process (flag_rxcomplete = _false).

To add a second port (i.e. capable of controlling two independent – but mutually exclusive SPI ports); simply add one more control byte to the serial packet. The serial packet would then look similar to: STX, PACKET_LEN, SPI_PORT, SPI_MODE, DATA (or STX, PACKET_LEN, SPI_MODE, SPI_TX_PACKET_LEN, SPI_RX_PACKET_LEN, SPI_DATA).

Code
Code :
'Author: languer (©2012)
'Pin Allocation:
	'PIN# Main_Fn                 Secondary_Fn
	'RA0 -> not used
	'RA1 -> not used
	'RA2 -> not used
	'RA3 -> not used
	'RA4 -> not used
	'RA5 -> not used
	'RA6 -> OSC
	'RA7 -> OSC
	'RB0 -> CTS# (RS232)
	'RB1 -> TX_RS232 (PC_RX)
	'RB2 -> not used
	'RB3 -> not used
	'RB4 -> RX_RS232 (PC_TX)
	'RB5 -> SPI_CS
	'RB6 -> SPI_SCK               PGC (Programming clock)
	'RB7 -> SPI_SDIO              PGD (Programming data)
'Usage Information:
	'RS232 Baud Rate: 19200bps
	'RS232 Handshake: Uses CTS to indicate to PC that MCU is ready to receive next command
	'0.1 second timeout on UART communications (packet must not take longer than 0.1sec to arrive)
'Version Info:
	'v1
	'->data format: STX,PACKET_LEN,SPI_MODE,DATA
		'where STX is start of character,
		'PACKET_LEN is number of data bytes to expect (maximum packet length: 32_bytes)
		'SPI_MODE is the SPI mode (1 or 2)
	'->SPI modes: 1 or 2
		'SPI Mode 1 for data on rising edge of clock,
		'SPI Mode 2 for data on falling edge of clock
		'CS is active low
 
'General Configuration
'for external 20MHz
Define CONFIG1L = 0x00
Define CONFIG1H = 0x02
Define CONFIG2L = 0x0e
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x00
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x03
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x03
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x03
Define CONFIG7H = 0x40
 
 
'Oscillator/Clock Configuration
	'Define CLOCK_FREQUENCY = 40
	Define CLOCK_FREQUENCY = 20
 
'HW UART Setup
	Hseropen 19200
 
'SPI Definitions
	Symbol spi_cs = RB5
	Symbol spi_sck = RB6
	Symbol spi_sdio = RB7
 
'Variable Declarations
	Const trisa1 = %11111111
	Const trisb1 = %00010100
 
	Symbol pc_tx = RB4  'rs-232 input
	Symbol pc_rx = RB1  'rs-232 output
	Symbol pc_cts_n = RB0  'rs232 cts# handshake signal
 
'rs223 interface constants
	Const stx = 0x81  'start-of-packet indicator
	Dim _true As Bit
	Dim _false As Bit
 
	_true = True
	_false = False
 
	Dim flag_rxinprogress As Bit
	Dim flag_rxcomplete As Bit
	Dim rxdata As Byte
	Dim rxdata_len As Byte
	Dim rxbuffer(32) As Byte
	Dim rxbuffer_cnt As Byte
 
 
'Main Program
main:
	Dim data As Byte
	Dim cnt As Byte
	Dim spi_mode As Byte
 
	WaitMs 2500
	Call init()
 
	PIR1.RCIF = _false
	INTCON.PEIE = _true  'enable peripheral interrupts
	PIE1.RCIE = _true  'enable RX UART interrupt
	Enable High  'enable general interrupt
	While _true
		'uart packet received succesfully
		If flag_rxcomplete = _true Then
			High pc_cts_n  'mcu busy indication
			spi_mode = rxbuffer(0)
			Call spi_init(spi_mode)
			Low spi_cs
			For cnt = 1 To rxbuffer_cnt
				data = rxbuffer(cnt)
				Call spi_send(spi_mode, data)
			Next cnt
			High spi_cs
			Low spi_sdio
			Low spi_sck
			flag_rxcomplete = _false
			Low pc_cts_n  'mcu idle indication
		Else
			'timeout on uart packet
			If PIR1.TMR1IF = _true Then
				Call disable_tmr1()
				flag_rxinprogress = _false
				flag_rxcomplete = _false
			Endif
		Endif
	Wend
End                                               
Proc init()
	Dim cnt As Byte
	AllDigital
	TRISA = trisa1
	TRISB = trisb1
	flag_rxinprogress = _false
	flag_rxcomplete = _false
	rxbuffer_cnt = 0
	rxdata_len = 0
	High spi_cs
	Low spi_sdio
	Low spi_sck
	Low pc_cts_n  'mcu idle indication
	'init tmr1 for 0.1sec timeout
	T1CON.T1CKPS1 = 1
	T1CON.T1CKPS0 = 1
	TMR1H = 0x0b
	TMR1L = 0xd6
	T1CON.TMR1ON = 0
	PIR1.TMR1IF = 0
End Proc                                          
Proc enable_tmr1()
	'set for 0.1sec
	TMR1H = 0x0b
	TMR1L = 0xd6
	T1CON.TMR1ON = 0
	PIR1.TMR1IF = 0
End Proc                                          
Proc disable_tmr1()
	'set for 0.1sec
	T1CON.TMR1ON = 0
	TMR1H = 0x0b
	TMR1L = 0xd6
	PIR1.TMR1IF = 0
End Proc                                          
Proc spi_init(mode As Byte)
	Select Case mode
		Case 1  'data on rising edge of clock
				High spi_cs
				Low spi_sck
				Low spi_sdio
				WaitUs 10
		Case 2  'data on falling edge of clock
				High spi_cs
				High spi_sck
				Low spi_sdio
				WaitUs 10
		Case Else
			'do nothing
	EndSelect
End Proc                                          
Proc spi_send(mode As Byte, data As Byte)
	Dim cnt As Byte
	Select Case mode
		Case 1  'data on rising edge of clock
			For cnt = 0 To 7
				Low spi_sck
				spi_sdio = data.7
				data = ShiftLeft(data, 1)
				High spi_sck
				ASM:        nop
				ASM:        nop
				ASM:        nop
				ASM:        nop
				ASM:        nop
				ASM:        nop
			Next cnt
			Low spi_sck
			Low spi_sdio
		Case 2  'data on falling edge of clock
			For cnt = 0 To 7
				High spi_sck
				spi_sdio = data.7
				data = ShiftLeft(data, 1)
				Low spi_sck
				ASM:        nop
				ASM:        nop
				ASM:        nop
				ASM:        nop
				ASM:        nop
				ASM:        nop
			Next cnt
			High spi_sck
			Low spi_sdio
		Case Else
			'do nothing
	EndSelect
End Proc                                          
 
On High Interrupt
	'Save System
	If PIR1.RCIF = _true Then
		Hserin rxdata
		If flag_rxinprogress = _false Then
			If rxdata = stx Then
				High pc_cts_n  'mcu busy indication
				flag_rxinprogress = _true
				flag_rxcomplete = _false
				rxbuffer_cnt = 0
				rxdata_len = 0
				Call enable_tmr1()
			Else
				'do nothing
			Endif
		Else
			If rxdata_len = 0 Then
					rxdata_len = rxdata
			Else
					rxbuffer(rxbuffer_cnt) = rxdata
					rxbuffer_cnt = rxbuffer_cnt + 1
				If rxdata_len = rxbuffer_cnt Then
					rxbuffer_cnt = rxbuffer_cnt - 1
					flag_rxinprogress = _false
					flag_rxcomplete = _true
				Endif
			Endif
		Endif
	Endif
	PIR1.RCIF = _false
Resume

How to arrive at the proper TMR1 values:
UART Timeout Calculation.png
Attached Thumbnails Attached Images

Comments

Electronic Circuits  |  Learning Electronics

Join our community with over 100,000 Members! It's free, easy and when you're logged in you have many more features! Click to register.
Page Time: 0.07595 seconds      Memory: 7,838 KB      Queries: 25      Templates: 0