- Blog entry posted in 'Electronics and Other Ramblings...', February 09, 2012.
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
'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
sudhirkumar.bctech, March 12, 2012
Dear friends, Am looking for any sample program to send and receive data through spi protocol using pic microcontroller...