Ring buffer hardware Usart


Closed Thread
Results 1 to 9 of 9

Hybrid View

  1. #1
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,115


    Did you find this post helpful? Yes | No

    Default

    It just kept on triggering the INT and after many changes (which led to a spaggeti program) I gave up.

    I just used the good ol' array transmit like this: Hserout [str array\n].

    When I feel like in a good mood I may try it again and see how it goes.

    As for the Rx Buffer, you ideas are good.

    I once tried the index pointer with a long array and no end of fle check. If characters kept coming then just over writen the previous characters in the array.

    Ioannis

  2. #2
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,604


    Did you find this post helpful? Yes | No

    Default

    Hi,
    I just made a quick and dirty test here using DT_Ints. The Main routine waits for PortB.0 going low, when it does it enables the TX interrupt. The TX interrupt service routine extracts characters from the buffer array and puts them in the TX register of the USART. When it sees a CR it disables the interrupt.
    Code:
    '****************************************************************
    '*  Name    : HWTX.BAS                                          *
    '*  Author  : Henrik Olsson                                     *
    '*  Notice  : Copyright (c) 2010 Henrik Olsson 2010             *
    '*          : All Rights NOT Reserved - use as you see fit.     *
    '*  Date    : 2010-11-16                                        *
    '*  Version : 0.0                                               *
    '*  Notes   : Test for interrupt based USART transmit using     *
    '*          : DT_ints-18 on a 18F4520                           *
    '****************************************************************
    DEFINE LOADER_USED 1                ' We're using a bootloader
    DEFINE OSC 20                       ' 20Mhz x-tal is used
    DEFINE HSER_BAUD 38400              ' Baudrate is 38400
    CMCON = 7                           ' Comparators OFF 
    ADCON1 = %00001111                  ' No analog inputs
    TRISC.7 = 1                         ' RxPin is input
    TRISC.6 = 0                         ' TxPin is output
    TRISB.0 = 1                         ' PortB.0 is input
    TxBuffer VAR BYTE[128]              ' Transmit buffer array.
    TxPointer VAR Byte                  ' Pointer into the above array
    INCLUDE "DT_INTS-18.bas"            ' Include Darrels interrupt engine.
    INCLUDE "ReEnterPBP-18.bas"         ' And the stub needed for interrupts in PBP 
     
    ASM                                 ; Set up the USART transmit interrupt.
    INT_LIST  macro     ; IntSource,   Label,    Type, ResetFlag?
            INT_Handler    TX_INT,   _USART_TX,   PBP,    no
        endm
        INT_CREATE                      ; Creates the interrupt processor
    ENDASM
    Boot:
      HSEROUT ["Program start",13]        ' A dummy HSEROUT here to init the USART and show we're alive.
     
      ' Now load the array with something we want to send. The string is, in this case, terminated with a CR (13).
      ArrayWrite TxBuffer,["This is the TX Array Buffer and we're sending it with an interupt based routine",13]
     
    Main: 
      If PortB.0 = 0 then                 ' PortB.0 going low is what
        TxPointer = 0                     ' Initialize pointer to beginning of array
    @   INT_ENABLE   TX_INT               ; Enable USART TX interrupt  
        Pause 100                         ' Simple debounce for the button
      ENDIF
      Goto Main                           ' And do it again.
     
    USART_TX:
      TXREG = TxBuffer[TxPointer]       ' Load character from array into USART TX register
      If TxBuffer[TxPointer] = 13 then  ' If that character was a CR we're done so we.....
    @   INT_DISABLE  TX_INT             ; ...disable the any further USART TX interrupts.
      ELSE                              ' If the character was not a CR we.....
        TxPointer = TxPointer + 1       ' ...increase prepare to send the next character.
      ENDIF
    @ INT_RETURN                        ; And exits the interrupt.
    Seems to work here, try it out if you like.

    /Henrik.

  3. #3


    Did you find this post helpful? Yes | No

    Default

    Thanks for all the replies very useful.

    Can my ring buffer RX routine below coexist with your TX routine I wonder?
    Can you have two interrupt driven things going on?

    Code:
    '-------------------------------------
    '        PBP BCM CODE 8mhz 1963 Words
    '-------------------------------------
    
    'MPASM Config
    @ __config _CONFIG1, _INTRC_IO & _WDT_OFF & _LVP_OFF & _MCLR_OFF & _CP_OFF
    @ __config _CONFIG2, _IESO_OFF & _FCMEN_OFF
    
    DEFINE OSC 8 			'Set oscilator speed to 8mHz 
    OSCCON = %01111000 		'8 Mhz
    CMCON  = %00000111 		'COMPARATORS OFF
    CCP1CON = 0             	'COMPARATORS OFF
    CVRCON = 0              	'COMPARATORS OFF
    INTCON = 0 		       	'Disable interrupts
    TRISB = %00000100 		'SET PORTB RB2(RX) as input, others to OUTPUT
    TRISA = %11110111 		'SET PORTA AS INPUTS except PORTA.3
    
    ANSEL  = %00000001      	'AN0 Analog Input 
    ADCON0 = %01000001		'Turns A/D on, AN0  Fosc/16
    ADCON1 = %11000000      	'Right justified and Fosc/16
    
    '-----------------------------------------------------------------------------
    INCLUDE "DT_INTS-14.bas"
    INCLUDE "ReEnterPBP.bas"     	'Include if using PBP interrupts
    
    ASM
    INT_LIST  macro    ;IntSource,        Label,       Type,    ResetFlag?
            INT_Handler    RX_INT,      _INT_Serin,     PBP,        no
        endm
        INT_CREATE               	;Creates the interrupt processor
    ENDASM
    
    @   INT_ENABLE   RX_INT     	;Enable external (INT) interrupts
    '-----------------------------------------------------------------------------
    
    
    'Setup the hardware USART for 9600 baud
    
    DEFINE HSER_BAUD 9600		'Set Baud rate to 9600bps
    DEFINE HSER_BITS 9		'Set to 9 bit mode
    DEFINE HSER_EVEN 1		'Set Even Parity
    DEFINE HSER_CLROERR 1 		'Clear overflow error automatically
    
    'Debug is used as it is the fastest and smallest serial routine to drive the Lcd display
     
    DEFINE DEBUG_REG PORTB		'Set Debug pin port B
    DEFINE DEBUG_BIT 4		'Set Debug pin bit for Lcd Display PORTB.4
    'DEFINE DEBUG_BAUD 38400	'Set Debug baud rate 38400 approx 3840 cps or 0.26ms per character
    DEFINE DEBUG_BAUD 9600		'Set Debug baud rate 9600 approx 960 cps or 1ms per character
    DEFINE DEBUG_MODE 0		'Set Debug mode: 0 = true, 1 = inverted (T=True Idle High)(N=Inverted Idle Low)
    DEFINE DEBUG_PACING 1000	'Set Debug Character Pacing mode to 1ms between bytes
    
    include "modedefs.bas"		'Allows the use of the standard serin/serout command  
    
    
    'Variables Constants and I/O definitions
    
    '------------------------ Variables 16bit --------------------------------------
    
    Amps 	  var WORD		'Amps Word Variable
    Soc	  var WORD		'Soc Word Variable
    TempH	  var WORD		'High Temperature Word Variable
    TempL	  var WORD		'Low Temperature Word Variable
    Gen1      var WORD      	'Gen1 General variable & Key input up/down/left/right/centre
    Watts	  var WORD		'IMA Power in Watts (Battery Volts x Battery Amps)
    MaxWatts  var WORD		'Maximum IMA Power in Watts during trip
    Errors    var WORD		'Number of RS485 Data Checksum Errors
    Packets   var WORD		'Number of RS485 Data Packets
    
    '------------------- Variables 8bit --------------------------------------------
    
    Volts 	  var BYTE		'Volts Byte Variable (0-255)
    BCM87 	  var BYTE[11]		'Define BCM87 as a Byte array (12 Bytes 0-11) (BCM87 = BCM Data)
    BCMAA	  var BYTE[11]		'Define BCMAA as a Byte array (12 Bytes 0-11) (BCMAA = BCM Data)
    Cnt 	  var BYTE		'General Byte Counter Variable (0-255)
    Text 	  var BYTE		'General Byte Text Variable (0-255)
    Gen0	  var BYTE		'Gen0 is a Byte variable (0-255)
    Config    var BYTE		'Gauge Config Byte (8 bits)
    AmpSign   var BYTE      	'Amps Sign Byte Variable (43 = +) (45 = -)
    TempHSign var BYTE		'TempH Sign Byte Variable (43 = +) (45 = -)
    TempLSign var BYTE		'TempL Sign Byte Variable (43 = +) (45 = -)	
    CheckSum  var BYTE		'BCM Data Checksum calculation Byte
    MaxVolts  var BYTE		'Maximum Voltage during trip
    MinVolts  var BYTE		'Minimum voltage during trip
    MaxAsst	  var BYTE		'Maximum Assist Amps during trip
    MaxRegen  var BYTE		'Maximum Regen Amps during trip
    MaxTemp   var BYTE		'Maximim Temp during trip
    MinTemp	  var BYTE		'Minimum Temp during trip
    MaxSoc	  var BYTE		'Maximum OEM Soc during trip
    MinSoc	  var BYTE		'Minimum OEM Soc during trip
    Adr1      VAR BYTE      	'Number for start of menu data
    Adr2      VAR BYTE      	'Number for end of menu data
    Display   VAR BYTE      	'Display Mode 0 = Normal, 1 =  Binary, 2 = Max/Min, 3 = Splash Screen
    
    
    'PortA Input Variables
    OverV  VAR PORTA.0		'Define PortA.0 Pin as OverV  (Over Voltage Input)  (Low = Over V)
    UnderV VAR PORTA.7		'Define PortA.7 Pin as UnderV (Under Voltage Input) (Low = Under V)
    
    'PortA Output Variables
    Spare VAR PORTA.3          	'Define PortA.3 Pin as Data Out 
    
    'PORTB Input Variables
    BcmIn Var PORTB.2       	'Define PortB.2 Pins as RS485 In
    
    'PORTB Ouput Variables
    Led1  VAR PORTB.0		'Define PortB.0 Pin as Led1
    Led2  VAR PORTB.1		'Define PortB.1 Pin as Led2
    Piezo VAR PORTB.3       	'Define PortB.3 Pin as Piezo
    BcmOut Var PORTB.5       	'Define PortB.5 Pins as RS485 Out
    
    ;-- Place a copy of these variables in your Main program -------------------
    ;--   The compiler will tell you which lines to un-comment                --
    ;--   Do Not un-comment these lines                                       --
    ;---------------------------------------------------------------------------
    
    ;wsave   VAR BYTE    $20     SYSTEM      ' location for W if in bank0
    ;wsave   VAR BYTE    $70     SYSTEM      ' alternate save location for W 
                                             ' if using $70, comment wsave1-3
    
    ' --- IF any of these three lines cause an error ?? ------------------------
    '       Comment them out to fix the problem ----
    ' -- Which variables are needed, depends on the Chip you are using -- 
    ;wsave1  VAR BYTE    $A0     SYSTEM      ' location for W if in bank1
    ;wsave2  VAR BYTE    $120    SYSTEM      ' location for W if in bank2
    ;wsave3  VAR BYTE    $1A0    SYSTEM      ' location for W if in bank3
    
    
    '***********************************************************************  
    
    
    'Alias & Vars
    RCIF VAR PIR1.5             	'Receive  interrupt flag (1=full , 0=empty)
    TXIF VAR PIR1.4             	'Transmit interrupt flag (1=empty, 0=full)
    OERR VAR RCSTA.1            	'Alias OERR (USART Overrun Error Flag)
    CREN VAR RCSTA.4           	'Alias CREN (USART Continuous Receive Enable)
    BufMax CON 48              	'Sets the size of the ring buffer
    Buffer VAR BYTE[BufMax]    	'Array variable for holding received characters
    Ptr_in VAR BYTE             	'Pointer - next empty location in buffer
    Ptr_out VAR BYTE            	'Pointer - location of oldest character in buffer
    Bufchar VAR BYTE            	'Stores the character retrieved from the buffer
    ErrFlag VAR BYTE            	'Holds error flags
    ptr_in = 0                  	'Clear buffer pointer (in)
    ptr_out = 0                 	'Clear buffer pointer (out)
    Errflag = 0                 	'Clear error flag
    
    
    '***********************************************************************  
    
    'Skip over the interupt handler & subroutines
    
    	debug 254,1                    		'Clear Screen   
    	goto MainLoop
    
    '***********************************************************************  
    
    '-------------------------------------
    ' INTERUPT HANDLER
    '-------------------------------------
    
    INT_Serin:                  			'Serial Interrupt routine
    
    	IF OERR Then usart_error 		'Check for USART errors
    	ptr_in = (ptr_in + 1)       		'Increment ptr_in pointer (0 to 63)
    	IF ptr_in > (BufMax-1) Then ptr_in = 0 	'Reset pointer if outside of buffer
    	IF ptr_in = ptr_out Then Buffer_Error	'Check for buffer overrun
    	HSerin [buffer[ptr_in]]     		'Read USART and store data in next empty location
    	IF RCIF Then INT_Serin 			'Check for another character while we're here
    
    @ INT_RETURN           				;Return to program
    
    	Buffer_Error:               		'Error - Run out of buffer space
    
    	errflag.1 = 1               		'Set the error flag for software
    
    'Move pointer back to avoid corrupting the buffer.
    'MIN insures that it ends up within the buffer. 
    
    	ptr_in = (ptr_in - 1) MIN (BufMax - 1) 
    	HSerin [buffer[ptr_in]]     		'Overwrite the last data stored (clear the int.)
    
    USART_Error:                			'Error - USART has overrun (data too fast?)
    
    	errflag.0 = 1               		'Set the error flag for hardware 
    
    @ INT_RETURN           				;Return to program
    
    
    '-------------------------------------
    ' Subroutines
    '-------------------------------------
    
    GetBuf:     					'Move the next character in buffer to bufchar
    
    @ INT_DISABLE  RX_INT       			;Dont want to interupt this, so Disable interupts
    
    ptr_out = (ptr_out + 1)     			'Increment ptr_out pointer (0 to 63)                           
    IF ptr_out > (BufMax-1) Then ptr_out = 0  	'Reset pointer if outside of buffer 
    bufchar = buffer[ptr_out]   			'Read buffer location
    
    @ INT_ENABLE  RX_INT        			;All done, Enable interupts
    
    Return
    
    
    '-------------------------------------
    ' Error Handler
    '-------------------------------------
    
    ErrorHandler:					'Display error message if buffer has overrun
    	
    	IF errflag.1 Then               	'Determine the error
        	DEBUG 254,128,"Buffer Overflow" 	'Display buffer error
    	Else
        	DEBUG 254,128,"USART Overrun"   	'Display usart error
    	EndIF
    
    	errflag = 0 				'Reset the error flag
    	CREN = 0 				'Disable continuous receive to clear overrun flag
    	CREN = 1            			'Enable continuous receive
    
    	GoTo MainLoop       			'Errors cleared, time to work.
    
    '-------------------------------------
    ' RS485 Passthru Test
    '-------------------------------------
    
    MainLoop:
    
    	IF errflag Then ErrorHandler    	'Handle error if needed
    	IF ptr_in = ptr_out Then MainLoop   	'loop if nothing in buffer
    
    	GoSub GetBuf   				'Get a character from buffer (stored in bufchar) 
    	HSEROUT [BufChar]   			'Send the character
    	
    	goto MainLoop  				'Loop forever
    
    
    END
    Last edited by retepsnikrep; - 16th November 2010 at 23:08.

  4. #4
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,604


    Did you find this post helpful? Yes | No

    Default

    Hi,
    Yes, you can have multiple interrupts and I can't see why the transmit interrupt routine wouldn't work with your code. Just remember that you need a way to determine when the last character has been sent. In my example I used the CR character but as said before it might be better to maintain a pointer (like you are doing in the receive buffer) and stopping after n number of bytes.

    /Henrik.

  5. #5
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,115


    Did you find this post helpful? Yes | No

    Default

    Hi Henrik.

    Thanks for the snippet. I test it on a 877 at 4MHz and works very good. As expected...

    My mistake when I tried the TX interrupts must have been the Reset flag that I was set it to YES.

    Ioannis

Members who have read this thread : 1

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts