• 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.1

    Blog entry posted in 'Electronics and Other Ramblings...', February 11, 2012.

    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:
    70249

    Comments
 

EE World Online Articles

Loading

 
Top