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
Email Blog Entry