• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

RS-232 SPI CONTROLLER – part 3

    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

    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
    sudhirkumar.bctech, March 12, 2012
    Dear friends, Am looking for any sample program to send and receive data through spi protocol using pic microcontroller...
 

EE World Online Articles

Loading

 
Top