News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

Interrupt for USART

Started by chris_cb_uk, Oct 27, 2021, 05:21 PM

Previous topic - Next topic

chris_cb_uk

Hi all, I'm establishing a 2 way communication between pics separated over fibre over quite a distance.  I have comms working of a fashion using timeout's to jump to the next sequence to avoid hanging i.e. using the wait function, however thinking that having the pics running on interrupts for their receive would be the best solution to make sure I'm not missing bytes from overflowing and or the programs are running efficiently.  I'm poking I2C sensors and Dallas devices to transmit their values and waiting for these to reply is causing some issues.

I'm using 18F4550 using hrsout on the hardware EUSART ports, I've never dealt with interrupts but understand the flags I'm looking for are RCIF 1 being full, 0 being empty.  I just need a little help in how to correctly assign the interrupt, calling the function and how to restore out of it.

Any help appreciated.

Chris

TimB

#1
Les in the samples has a USART interrupt example

I have included some I got from a bit of code I have. Loads of non useful stuff but it covers most of what you need.

I highly recommend you use a timed packet system. Where you time the period between data. If the data does not all come through then after it times out you reset your statemachine to ignore that packet and wait for the next one.

The Modbus system kind of works like that. With work you can also implement an ACK system so if the data sent has a CRC (it needs to) you can send that back to say OK got some data.
The RX code should also check the CRC is right before sending the ACK. The TX side can time for the ACK. If it does not get it within x ms then it resends. Perhaps for for x times. If after x retries it can signal data lost to slave and take action.

; Set up the usart to run at the right speed and interrupt on high level ints

;Usart 1
;Calculated Baudrate = 38462 @ Xtal 48MHz, Error = 0.16%
    RCSTA = 144 ; Enable continuous receive
    TXSTA = 36  ; Enable transmit, BRGH = 1
    SPBRG = 77  ; Baud Rate Generator Value

    ;Calculated Baudrate = 38462 @ Xtal 48MHz, Error = 0.16%
    RCSTA2 = 144 ; Enable continuous receive
    TXSTA2 = 36  ; Enable transmit, BRGH = 1
    SPBRG2 = 77  ; Baud Rate Generator Value

;Usart 2
; ENABLE USART RECEIVE INTERRUPTS
    RC1IP = 1                                                                     ; USART1 HAS HIGH PRIORITY
    RC2IP = 1                                                                     ; USART2 HAS HIGH PRIORITY
    RCIE = 1
    RCIE = 1
    RC2IE = 1
    CREN1 = 1
    CREN2 = 1
    SPEN1 = 1
    SPEN2 = 1
   
    TX1IP = 1                                                                     ; TX Usart Int is high priority
    TX2IP = 1                                                                     ; TX Usart Int is high priority
    TX1GenDataSent = True                                                         ; Info flags
    TX2DataSent = True
   
    TRISC.6 = 0                                                                   ' Set the TX ports as output so the data can come out
    TRISB.6 = 0


;-------------------------------------------------------------------------------

;*=============================================================*
;   Usart interrupt
;   Hanldes the RX and TX of data
;*=============================================================*


Usart_Int:
    Reset_Bank
    If OERR1 = 1 Then GoTo USART_ERR1                                           ; Check for usart1 overrun
    If OERR2 = 1 Then GoTo USART_ERR2                                           ; Check for usart1 overrun

    HiIntFSRSave = FSR_0                                                        ; Save the FSR Reg

    If RCIF = True Then                                                         ; If this is a RX1 interrupt
        HighIntTemp = RCREG1                                                    ; Make a working copy of the data
        RX1DataBuffer[RX1DataBufferPointer] = HighIntTemp                       ; Load the data into our buffer
        If RX1DataBufferPointer < RX1DataBufferSize Then                        ; make sure we are below our buffer size
            Inc RX1DataBufferPointer                                            ; Move our pointer up
            RX1FrameTimer = RX1FrameTimerReloadVal
        Else                                                                    ; too much data to quick reset needed
            RX1FrameTimer = RX1FrameTimerReloadVal
            RX1DataBufferPointer = 0                                            ; Reset the buffer pointers and timers
        EndIf
    EndIf

    If RC2IF = True Then                                                        ; If this is a RX2 interrupt
        HighIntTemp = RCREG2                                                    ; Make a working copy of the data
        RX2DataBuffer[RX2DataBufferPointer] = HighIntTemp                       ; Load the data into our buffer
        If RX2DataBufferPointer < RX2DataBufferSize Then                        ; make sure we are below our buffer size
            Inc RX2DataBufferPointer                                            ; Move our pointer up
        RX2FrameTimer = RX2FrameTimerReloadVal
        Else                                                                    ; too much data to quick reset needed
            RX2FrameTimer = RX2FrameTimerReloadVal
            RX2DataBufferPointer = 0                                            ; Reset the buffer pointers and timers
        EndIf
    EndIf

    ; Code to send the data from the TX buffer1
    If TX1IE = 1 Then                                                           ; Only do the rest if the TX1 interrupts are enabled, its our way to control the system
        If TX1IF = True Then                                                    ; If this is a TX interrupt
            If TX1PacketType = TX1PType_MainData Then
                If TX1GenDataBufferPointer >= TX1GenBufferCount Then            ; Check if there is more data to send
                    TX1IE = 0                                                   ; Buffer empty so turn of interrupts for now
                    TX1FrameTimer = TX1FrameTimerReloadVal
                Else
                    TXREG1 = TX1GenDataBuffer[TX1GenDataBufferPointer]          ; Send the data
                    Inc TX1GenDataBufferPointer                                 ; Move the pointer to the next byte
                    TX1GenDataSent = False                                      ; Mark there is still data to send
                    TX1FrameTimer = TX1FrameTimerReloadVal
                EndIf
            Else
                If TX1MsgReplyBufferPointer >= TX1MsgReplyPacket Then           ; Check if there is more data to send
                    TX1IE = 0                                                   ; Buffer empty so turn of interrupts for now
                    TX1FrameTimer = TX2FrameTimerReloadVal
                Else
                    TXREG1 = TX1MsgReplyBuffer[TX1MsgReplyBufferPointer]        ; Send the data
                    Inc TX1MsgReplyBufferPointer                                ; Move the pointer to the next byte
                    TX1GenDataSent = False                                      ; Mark there is still data to send
                    TX1FrameTimer = TX1FrameTimerReloadVal
                EndIf
            EndIf
        EndIf
    EndIf

    ; Code to send the data from the TX buffer2
    If TX2IE = 1 Then                                                           ; Only do the rest if the TX1 interrupts are enabled, its our way to control the system
        If TX2IF = True Then                                                    ; If this is a TX interrupt
            If TX2PacketType = TX2PType_MainData Then
                If TX2DataOutBufferPointer >= TX2BufferCount Then               ; Check if there is more data to send
                    TX2IE = 0                                                   ; Buffer empty so turn of interrupts for now
                    TX2FrameTimer = TX2FrameTimerReloadVal
                Else
                    TXREG2 = TX2GenDataBuffer[TX2DataOutBufferPointer]          ; Send the data
                    Inc TX2DataOutBufferPointer                                 ; Move the pointer to the next byte
                    TX2DataSent = False                                         ; Mark there is still data to send
                    TX2FrameTimer = TX2FrameTimerReloadVal
              EndIf
          Else
              If TX2MsgReplyBufferPointer >= TX2MsgReplyPacket Then           ; Check if there is more data to send
                    TX2IE = 0                                                   ; Buffer empty so turn of interrupts for now
                    TX2FrameTimer = TX2FrameTimerReloadVal
              Else
                    TXREG2 = TX2MsgReplyBuffer[TX2MsgReplyBufferPointer]        ; Send the data
                    Inc TX2MsgReplyBufferPointer                                ; Move the pointer to the next byte
                    TX2DataSent = False                                         ; Mark there is still data to send
                    TX2FrameTimer = TX2FrameTimerReloadVal
              EndIf
          EndIf
        EndIf
    EndIf

USART_EXIT:
    FSR_0 = HiIntFSRSave
    USART_EXIT2:
    Retfie Fast

USART_ERR1:                                                                     ; Handle a usart overrun error
    WREG = RCREG1                                                               ; Clear the regs
    CREN1 = 0
    CREN1 = 1
    TX1FrameTimer = 0                                                           ; Clear the regs
    RX1DataBufferPointer = 0
    GoTo Usart_Int                                                              ; Jump back to the start
   
USART_ERR2:                                                                     ; Handle a usart overrun error
    WREG = RCREG2                                                               ; Clear the regs
    CREN2 = 0
    CREN2 = 1
    TX2FrameTimer = 0                                                           ; Clear the regs
    RX2DataBufferPointer = 0                                                    ; Reset the buffer pointer
    GoTo Usart_Int



chris_cb_uk

Thanks Tim, I've picked out some key points in your code that I was lacking understanding of for interrupts. 
Interesting about modbus, I have experience of this from PLC backgrounds in a previous life programming S7 Siemens Ladder.  I think this will be the most robust solution for avoiding clashes, time outs and enabling everything to be clocked in, and out with certainty backwards and fourth.