Electronic Circuits and Projects Forum



languer

RS-232 SPI CONTROLLER – part 3

by languer , 9th February 2012 at 06:16 AM (1925 Views)
After a bit more playing with this I have something that kind of works for bidirectional communications. Here it should be obvious why we are using the CTS line to tell the PC when the MCU is ready for the next command/request. For the unidirectional SPI controller we used the CTS as well, but we could’ve use a special character (or sequence of characters) on the received RS232 to let the PC know it was ready. For the bidirectional case, that is not true. Since we may be expecting a reply back from the PC, we must have a robust mechanism to tell the PC it is ready for more data – thus the use of the CTS line.

So what are the restrictions?
• First, the PC side must use the CTS handshaking.
• Second, it cannot revive more than 255 bytes at once. Why you may ask? We defined the receive data as a byte – bytes only reach 255.
• Third, 'PACKET_LEN should always be 'SPI_TX_PACKET_LEN + 3. This is so because the Packet includes the SPI_MODE, SPI_TX_PACKET_LEN, and SPI_RX_PACKET_LEN (i.e. three additional bytes the SPI_TX_PACKET_LEN is not aware of.

I’m still not sold on the packet information (since PACKET_LEN, and SPI_TX_PACKET_LEN represent almost the same; and there can be on without the other.

Now to find some simple device I would like to read back from…

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
'Version Info:
	'v1
	'->adds bi-directional capability to SPI port
		'this allows to read up to 32_bytes of data, as well as to send this much data
	'->updated data format: STX,PACKET_LEN,SPI_MODE,SPI_TX_PACKET_LEN,SPI_RX_PACKET_LEN,SPI_DATA
		'where STX is start of character,
		'PACKET_LEN is number of data bytes to expect (maximum packet length: 35_bytes)
		'SPI_TX_PACKET_LEN is number of data bytes to be sent from PC (max: 32_bytes)
		'SPI_RX_PACKET_LEN is number of data bytes to be received by PC (max: 255_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 = 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 packet_len As Byte
	Dim data_buffer(32) As Byte
	Dim data_buffer_cnt As Byte
 
 
'Main Program
main:
	Dim tmpbyte As Byte
	Dim data As Byte
	Dim cnt As Byte
	Dim spi_mode As Byte
	Dim spi_rxdata_len As Byte
	Dim spi_txdata_len As Byte
 
	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
		If flag_rxcomplete = _true Then
			High pc_cts_n  'mcu busy indication
			spi_mode = data_buffer(0)
			spi_txdata_len = data_buffer(1)
			spi_rxdata_len = data_buffer(2)
 
			'validate tx packet length
			tmpbyte = packet_len - 3
			If spi_txdata_len > tmpbyte Then
				spi_txdata_len = tmpbyte
			Endif
 
			'initialize spi port
			Call spi_init(spi_mode)
			Low spi_cs
 
			'send data to SPI device
			If spi_txdata_len = 0 Then
				'do nothing
			Else
				spi_txdata_len = spi_txdata_len + 2  'first data byte to be transmitted is on location 3, shift tx_buffer by three (since index starts at 0, the 3 becomes 2)
				For cnt = 3 To spi_txdata_len  'first data byte to be transmitted is on location 3
					data = data_buffer(cnt)
					Call spi_send(spi_mode, data)
				Next cnt
			Endif
 
			'receive data from SPI device
			If spi_rxdata_len = 0 Then
				'do nothing
			Else
				spi_rxdata_len = spi_rxdata_len - 1  'compensate for array starting at 0
				For cnt = 0 To spi_rxdata_len
					data = spi_receive(spi_mode)
					Hserout data
				Next cnt
			Endif
			High spi_cs
			Low spi_sdio
			Low spi_sck
			flag_rxcomplete = _false
			Low pc_cts_n  'mcu idle indication
		Endif
	Wend
End                                               
 
Proc init()
	AllDigital
	TRISA = trisa1
	TRISB = trisb1
	flag_rxinprogress = _false
	flag_rxcomplete = _false
	data_buffer_cnt = 0
	packet_len = 0
	spi_txdata_len = 0
	spi_rxdata_len = 0
	High spi_cs
	Low spi_sdio
	Low spi_sck
	Low pc_cts_n  'mcu idle indication
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                                          
 
Function spi_receive(mode As Byte) As Byte
	Dim data As Byte
	Dim cnt As Byte
	Select Case mode
		Case 1  'data on rising edge of clock
			Low spi_sck
			For cnt = 0 To 7
				High spi_sck
				data.0 = spi_sdio
				data = ShiftLeft(data, 1)
				Low 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
			High spi_sck
			For cnt = 0 To 7
				Low spi_sck
				data.0 = spi_sdio
				data = ShiftLeft(data, 1)
				High 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
	spi_receive = data
End Function                                      
 
On High Interrupt
	'Save System
	Dim data As Byte
	If PIR1.RCIF = _true Then
		Hserin data
		If flag_rxinprogress = _false Then
			If data = stx Then
				High pc_cts_n  'mcu busy indication
				flag_rxinprogress = _true
				flag_rxcomplete = _false
				data_buffer_cnt = 0
				packet_len = 0
			Else
				'do nothing
			Endif
		Else
			If packet_len = 0 Then
					packet_len = data
			Else
					data_buffer(data_buffer_cnt) = data
					data_buffer_cnt = data_buffer_cnt + 1
				If packet_len = data_buffer_cnt Then
					data_buffer_cnt = data_buffer_cnt - 1
					flag_rxinprogress = _false
					flag_rxcomplete = _true
				Endif
			Endif
		Endif
	Endif
	PIR1.RCIF = _false
Resume

Comments

    Dear friends,
    Am looking for any sample program to send and receive data through spi protocol using pic microcontroller...
    Dear friends,
    Am looking for any sample program to send and receive data through spi protocol using pic microcontroller...
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.07644 seconds      Memory: 7,897 KB      Queries: 24      Templates: 0