News:

;) This forum is the property of Proton software developers

Main Menu

Small RAM size big message over the serial port.

Started by keytapper, Jun 02, 2024, 03:57 PM

Previous topic - Next topic

keytapper

Hi there,

I'm trying to make the use of a minimal setup. So for the current MCU I'd like to solve with a serial control flow, rather than switching to a bigger MCU. The most reason is that I just have this MCU at home and using it for a simple test.

The following example needs a big review.

Device 12F1840
Xtal = 32
On_Hardware_Interrupt GoTo Isr
#Disable HRSOut

Config1 FOSC_INTOSC, WDTE_SWDTEN, PWRTE_ON, MCLRE_OFF, CP_OFF, CPD_OFF, _
        BOREN_OFF, CLKOUTEN_OFF, IESO_OFF, FCMEN_OFF
Config2 WRT_OFF, PLLEN_ON, STVREN_OFF,LVP_OFF

Declare Hserial_Baud 57600
Declare HSerial_Terminator = CR
Declare Hserial_TXSTA = %00100100
Declare Hserial_RCSTA = %10010000
Symbol GIE INTCON.7
Symbol PEIE INTCON.6
Symbol RCIE PIE1.5
Symbol RCIF PIR1.5
Symbol TXIF PIR1.4
Symbol TXIE PIE1.4
Symbol OUT_PIN PORTA.2
Symbol X_OFF 19
Symbol X_ON 17

Dim TXBUFSIZE As 32
Dim RXBUFSIZE As 64
Dim rxbuffer[RXBUFSIZE] As Byte
Dim txbuffer[TXBUFSIZE] As Byte
Dim rx_WR           As Byte System
Dim tx_RD           As Byte System
Dim tx_WR           As Byte System
Dim rx_RD           As Byte System
Dim txchar          As Byte
Dim rxchar          As Byte
Dim inchar          As Byte
Dim flags           As Word
Dim x_offFlag       As flags.14

'=============================Main=============================================

OSCCON = %01110000
WDTCON = %00011110
OPTION_REG = 0
WPUA = %00001010
LATA  = 0
TRISA = %00101010
PORTA = %00001000
Set GIE
Set PEIE
Set RCIE
WREG = RCREG

Do
  If rx_WR <> rx_RD Then
    rxchar = rxbuffer[rx_RD]
    HSerOut[rxchar]
    If rx_RD >= RXBUFSIZE Then
      If x_offFlag = 1 Then
        If TXIF = 1 Then
          TXREG = X_ON
          Set OUT_PIN
        End If
        Clear x_offFlag
      End If
      rx_RD = 0
    Else
      Inc rx_RD
    End If
  End If
Loop
'==============================================================================
End

$ifndef noshow
__hrsout1__:
  Clear GIE
  txchar = WREG
  txbuffer[tx_RD] = txchar
  Inc tx_RD
  If tx_RD >= TXBUFSIZE Then
    Clear tx_RD
  EndIf
  Set TXIE
  Set GIE
Return
$endif
'-----------------Interrupt Routine  ----------------------------------------
Isr:
Context Save
  If RCIE = 1 Then
    If RCIF = 1 Then
      Movlw 6
      Movlb 0x03
      Andwf RCSTA,W
      Movlb 0x00
      Bnz _UART_Error
      inchar = RCREG
      If inchar = X_OFF Or inchar = X_ON Then ISR_Next
      rxbuffer[rx_WR] = inchar
      Inc rx_WR
      If rx_WR >= RXBUFSIZE Then
        If TXIF = 1 Then
          Clear OUT_PIN
          TXREG = X_OFF
          Set x_offFlag
        End If
        rx_WR = 0
      EndIf
      GoTo ISR_Next
_UART_Error:
      WREG = RCREG
      Clear RCSTA.4
      Set RCSTA.4
    End If
  End If
ISR_Next:
  If  TXIE = 1 Then
    If TXIF = 1 Then
      TXREG = txbuffer[tx_WR]
      Inc tx_WR
      If tx_WR >= TXBUFSIZE Then
        Clear tx_WR
      EndIf
      If tx_WR = tx_RD Then
        Clear TXIE
      End If
    End If
  End If
Context Restore
I'm trying to catch the big messages with a pause. So mainly I'm looking when the buffer is full to remove enough character before restarting the circular buffer.
Currently I don't see the OUT_PIN switching and is not clear if the sender has accepted to stop the flow. Probably I should try to set up the sender with the control flow correctly.
Ignorance comes with a cost

tumbleweed

In my experience, software flow control (XON/XOFF) isn't immediate and tends to take a few character times to take effect depending on the hardware/code on the other end... plan on getting more characters after you send the XOFF before the transmitter stops sending.

Hardware flow control (RTS/CTS) usually works out better.

keytapper

I imagine that is preferable, but the pin count is sooo minimal.
For some attempt I may add a margin to the buffer boundary. I've improved the source and seems that is just to arrange for the TX buffer in a similar manner. But currently I've only a big incoming flow, rather than both directions.
startLoop:
  If rx_RD = rx_WR Then                   ' buffer empty
    RCREG = X_ON                          ' allow to receive
    DelayMS 100                           ' don't choke
    GoTo startLoop
  End If
8<---------------8<---------------8<---------------8<---------------8<--------
ISR:
 If RCIE = 1 Then
    If RCIF = 1 Then
      Movlw 6
      Movlb 0x03
      Andwf RCSTA,W
      Movlb 0x00
      Bnz _UART_Error
      rxbuffer[rx_WR] = RCREG
      Inc rx_WR
      bufspace = rx_WR // RXBUFSIZE
      If bufspace >= RXBUFSIZE Then        ' buffer is full
        RCREG = X_OFF                      ' put on hold
      End If
      If rx_WR >= RXBUFSIZE Then
        rx_WR = 0
      EndIf
      GoTo ISR_Exit
_UART_Error:
      WREG = RCREG
      Clear RCSTA.4
      Set RCSTA.4
    End If
  End If
ISR_Exit:
Context Restore
I found difficult to make a test and understand how the result are reliable.
Ignorance comes with a cost

trastikata

#3
Are you looking for creating a protocol for particular application or an universal UART solution?

You mentioned that you have control over the sender?

Why not software based RTS/CTS? Divide the package in chunks and assign TX/RX or RTS/CTS windows. Something a bit like the USB protocol.

tumbleweed

Why are you now writing the XON/XOFF into the RCREG?
You need to transmit them to the sender.

keytapper

Quote from: tumbleweed on Jun 03, 2024, 10:47 PMWhy are you now writing the XON/XOFF into the RCREG?
Alas I got an oversight  :o
Thank you to spot it on. It's right to send to the other party the command to hold on for a while.

Quote from: trastikata on Jun 03, 2024, 03:57 PMAre you looking for creating a protocol for particular application or an universal UART solution?
Well, for my purpose this time, it's to collect information from a modem. Therefore the maximum buffered data that I can allocate is merely 100 bytes, fortunately the modem accept the XON/XOFF control flow, but no hardware implementation on the modem side. Even though there was, I should have to go for another MCU to add the hardware control flow.
Ignorance comes with a cost