Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

Software UART issues

 
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR
View previous topic :: View next topic  
Author Message
njepsen

Bascom Member



Joined: 13 Aug 2007
Posts: 469

newzealand.gif
PostPosted: Fri Jun 26, 2020 6:55 am    Post subject: Software UART issues Reply with quote

I am using a sw UART with the Atmega 1284p, and i also have an onboard Raspberry Pi, which talks to the Atmega on a slow SW UART. All the hardware UARTS are talking to the more important things so are not available.
The issue i, having is trying to receive a 200byte string of text whilst there are interrupts going on. The first 50 or so char are received OK, then I get text mixed with non printable char.
I cant turn interrupts off because I use a timer to generate the system clock and another to keep the watchdog from barking/biting me.
Any advice?


The code for the receiver looks like this:
Code:

 '*******************************************************************************
$regfile = "m1284pdef.dat"                          
$crystal = 9830400                                        
$framesize = 800                                            
$hwstack = 550                                              '
$swstack = 550
$frameprotect = 1
config submode = old                                        'old =  need to declare subs or functions
$include "config_mmcsd_hc.bas"                            
$PROG &HFF , &HC7 , &HD0 , &HFD
 '==============================================================================

 '*****************************************************

Function pi_response(byval picommandstr  As String) As String

   
      Local Tempstr7 As String * 250
      Local Td As Long

  #if Pi_fitted = 1
'(
      This function runs a command and returns the response to the caller

      *******  VALID PI COMMANDS   *********
      upload,1   pi free to send audio files to the server
      upload,0  inhibit uploads
      status?  get status  from pi
      shutdown  tell pi to shutdown in an orderly manner. takes 30s
      pitakeboth    recording + image
      ssh,0
      ssh,1
      ppp,0  point to point coms on and off
      ppp,1
      startrecord,xx   start a recording xx seconds long
      stoprecord
      bitrate,nn   nn = 8,12,16,24,
      register,phonenumber     in format  "%2bnnnnnnnnnnn"
      Pi terminators;
      after all echos  $$ <CR>
      after all data ##   <CR>

     

      ')


      Tempstr7 = ""

      Td = Local_secl + 10                                  '10 secs

      If picommandstr <> "" Then
         Print #7 , picommandstr                            'send cmd to pi ser port

            Do
               Rxbyte = Inkey(#8)                              '#8 is pi sw uart ser port
               If Rxbyte <>0 Then
                  Tempstr7 = Tempstr7 + Chr(rxbyte)
               End If
            Loop Until Local_secl >= Td 'or rxbyte = 35         ' 35 = #  expected terminator  Td is time delay timeout.

         Delchars Tempstr7 , 32                              'remove spaces

         If Tempstr7 <> "" Then
                      Print #1 , ">> Pi said  " ; Tempstr7
         Else
            Print #1 , ">> no response from pi"
            Tempstr7 = "no response from pi"
         End If


         pi_response = Tempstr7                              'return
      end if

  #endif

End Function


 '******************************************************


(BASCOM-AVR version : 2.0.8.2 )

_________________
Neil
Back to top
View user's profile
JC

Bascom Member



Joined: 15 Dec 2007
Posts: 586
Location: Cleveland, OH

usa.gif
PostPosted: Fri Jun 26, 2020 4:48 pm    Post subject: Reply with quote

Interesting question.

I probably should stay out of this discussion as I don't know enough about how the SW UART works.

That said:
Probably not related to your problem, but how is Local_sec1 defined?
Does it roll over at 59 seconds, or count to some huge number?
If it rolls over at 59 to 0, then if it is at 56 seconds, and you add 10 sec for a timeout limit, it will never time out.
If it is a Word it will roll over about once every 17 hours, causing occasional errors, if it isn't reset elsewhere.

Because Bascom uses SW timing for the SW UARTS, (which leaves all of the HW T/Cs available to the programmer), any interrupts will obviously lengthen any SW delays. That likely makes the SW UART read a bit value too late, it is reading the following bit and missing one, giving a framing error.
HW UARTS. (IIRC), usually resynch on each Start Bit. One might expect the SW UART to do the same, (it seems reasonable). That makes it odd that you can receive 50 characters via the SW UART before you get errors.

If the problem was that you have too many interrupts firing and taking too long, delaying the reading of a bit within a byte, (and the SW UART does re-synch on the next Byte's Start Bit), then one would expect that the errors during ANY incoming character, and not that you would receive 50 characters correctly before the error showed itself.
So, perhaps the --> assumption <-- that the SW UART resynchs on each Start Bit is invalid?

A buffer overflow occurring after about 50 incoming characters seems unlikely, as that would likely give loss of bytes, not corrupted bytes, but again even that is uncertain as the SW UART implementation isn't known. It would certainly be worthwhile, however, to look at your buffer sizes, and ability to handle the incoming data streams in a timely manner, to make sure that that isn't the source of the problem. Testing here could include both decreasing and well as increasing buffer sizes to see the impact upon your ability to receive 50 characters before a problem occurs. (Does changing the buffer size change how many characters you can correctly receive, 25, 50, 100...?)

Program structure?
Obviously the goal is to not have any interrupts running when you are receiving data via a SW UART. So several approaches come to mind, (all untested!).
As you review your overall program structure, is it possible to shorten any of your ISRs? Can you change anything to jest setting a flag in the ISR and handling the processing within the Main Loop?

What is your System Clock ISR firing at? At your present SW UART baud rate, how many times will the System Clock ISR fire during the reception of a single byte? If your System Clock is firing multiple times during the timeframe for one byte to be received that would cause a cumulative error. Can you slow down your System Clock ISR Rate?

What is the Baud Rate error ( % ) for your current baud rate and micro's clock frequency? Your goal should be to have it be < 2 % for a HW USART, (Giving a possible error of (+) 2 % on one end, and (-) 2 % on the other device, for a total of 4% baud rate error, max, for reliable communications, IIRC). That works well for HW UARTs, but clearly doesn't apply as a safe operating range for a SW UART, especially if you are trying to run ISRs simultaneously.

If you are right on the edge of reliable communications, baud rate wise, then perhaps the ISRs are slowing the baud rate down to the point where it is impacting the data reception.

Normally, slowing a HW UART baud rate down won't impact the data reception IF the baud rate error remains unchanged, (lots of caveats here). However, for a SW UART slowing the baud rate down will increase the bit time for each bit. This would widen the window during which one had to read the bit's value.
This might, or might not, improve the situation. Recall that the longer bit time will also allow time for more ISRs to fire. So it might, or might not, improve the situation, depending upon the specifics of the program. If the overall ISR processing time is rather low, then slowing the SW UART baud rate might improve the system performance. It the micro is spending a lot of its processing time within ISRs, then lengthening the SW UART bit time likely won't improve the situation.

That said, slowing down the SW UART's baud rate is certainly an easy test to perform, although it might have an impact on other aspects of your system's data processing. (Assuming you have control over the baud rate at both ends of the comm link.)

Time for a processor change?
At the end of the day perhaps you have just reached a limitation on the data processing throughput you can achieve with the Mega.
Recall that the new AVRs, such as the AVR128DA48, can run in spec at 20 MHz, (3 or 5 volts), and have some new (Xmega type) features. I asked Bascom Support if they wanted me to send them a few for their tinkering and haven't heard back, but they are not (yet?) supported). The Xmegas are supported, and run in spec at 32 MHz. That gives one a tremendous increase in processing power, (both millions more clock cycles / Sec, and faster execution of every instruction, a double win). The larger ones also have up to 8 HW UARTS, (IIRC). If your ISRs execute much faster then there is less impact upon reading a SW UART bit within its given window. The AVR128DA48 has a two level priority interrupt controller, the Xmegas have a 3 level priority interrupt controller, which can also be helpful at times for structuring how multiple ISRs will be handled when they occur "simultaneously", (although perhaps not directly helpful regarding the usage of SW UARTS).

Last thought:
Many people dislike having multiple processors on a board for a given project. But if one thinks of adding a second micro as just another sensor or chip performing a given task, then it sometimes makes sense to do so. In this case the second processor's only purpose would be to handle several UART data links, and pass the incoming data on to the Master micro via one UART channel. The data from each of the channels would be places in defined packets, e.g. <A,X,Y,Z...>, Where following the Start of Packet character the next data element tells the Master Micro which device's data is contained within this packet. The second micro is functioning as a smart data collator / multiplexer.

Simply switching to an Xmega with more processing power and lots of HW UARTs might be an easier approach to a system upgrade.

Oh well, thought I'd share a few thoughts. Hopefully you will get your system up and running reliably!

JC
Back to top
View user's profile Visit poster's website
njepsen

Bascom Member



Joined: 13 Aug 2007
Posts: 469

newzealand.gif
PostPosted: Sat Jun 27, 2020 6:31 am    Post subject: Reply with quote

Hello JC, and many thanks for your comments and suggestions.
To answer some of your questions:
Local_sec1 is a long, so it wont roll over any time soon.
Yes I realize my ISRs will slow down my RTC, but the project is a telemetry system and communicates with a server every 15 minutes, & i sync the RTC at that time so time errors are not an issue.

In actual fact, i have not tested whether it is the interrupts that are causing the issue - I'm guessing really, based on the fact that i use another SW uart which also has the same issue but behaves much better if I turn off the ISRs. This 2nd SW uart is a debug port, which provides a real time commentary on whats happening to a local serial connector, and I can plug a laptop in here and see whats going on. Also - if I limit the number of characters coming from the Pi, the problem goes away.
As I said before -its difficult to stop the ISRs because that causes a watchdog after a few seconds.
I dont know how the SW UART works and how many samples per bit, where it syncs etc but it must be quite smart to handle the full range of baud rates.
You asked - does changing the buffer size help. Which buffer?
I have 2 timer ISRs, and very little happens in each.
Code:

The other serial coms are not talking when this problem arises,(because ser coms is under program control, not asynchronous)  so thats probably not the issue.

'******************************************************************************
timer1overflow:
 
 timer1 = 55936

 decr wd_holdoffw
 toggle heartbeatLED                
 if wd_holdoffw > 0 then
   dn20 = 0
   reset watchdog             'processor WD, set to 8sec. This is the only time in the whole code this happens
 else
   'the following code is very rarely if never . Causes system reset after 8 secs.
    print #1 , "WDHoldoff FAIL"
    if dn20 = 0 then Call Write_err_message( "WDHoldoff FAIL")       'write once only
    dn20 = 1
 end if


return
'***************************************************************************************
Timer2overflow:
'***************************************************************************************
 'T2 rolls over 37.5x per seconds
 'incr secflagb
                                           'used to do 1 sec profile Lmax check in main loop
Return

 '*****************************************************************************
Timer3overflow:
'********************************************************************************
   'T3 rolls over every 1 second

   Timer3 = 55936                                           '65536 - 9600x1

   Incr 1_secflagb                                          'used to read profile Lmax
   Incr Unix_time                                           'used in many places for recordings and images
   Incr Local_secl                                           'RTC

Return



end


Processor Change:
You may be right. I have about 70 of these things out in the field, but a new PCB would not be the end of the world for the next version.

_________________
Neil
Back to top
View user's profile
JC

Bascom Member



Joined: 15 Dec 2007
Posts: 586
Location: Cleveland, OH

usa.gif
PostPosted: Sat Jun 27, 2020 10:50 pm    Post subject: Reply with quote

Which buffers...
Um, my mistake.

As I was thinking about the SW UART issue I forgot that you are reading the SW UART in the foreground, not within an interrupt driven, read a byte and stuff it in a buffer, background process.

JC
Back to top
View user's profile Visit poster's website
njepsen

Bascom Member



Joined: 13 Aug 2007
Posts: 469

newzealand.gif
PostPosted: Sun Jun 28, 2020 1:39 am    Post subject: Reply with quote

Good idea - i'll try that. Easy to do. You also got me looking at the xmega, which have some very powerful and useful advantages.
I'll get back to you re the interrupt driven SW uart.

_________________
Neil
Back to top
View user's profile
JC

Bascom Member



Joined: 15 Dec 2007
Posts: 586
Location: Cleveland, OH

usa.gif
PostPosted: Sun Jun 28, 2020 2:25 am    Post subject: Reply with quote

I think I wasn't clear above.

In the HW UART the module finds the Start bit, samples the data bits, puts the result in a HW register, and then sets a flag and then optionally generates an interrupt.
This is all performed without any foreground processing code on your part.

In Bascom, when the HW UART is configured for an interrupt driven, ring buffered, configuration, then once again the HW module does the low level work and the ISR grabs the incoming data byte, stuffs it in a ring buffer, (perhaps sets some internal error flags for parity error, framing error, etc.), and exits.
This is very fast, it only takes a few instructions to read a Byte, stuff it in a buffer, and adjust the buffer pointers.

The only actual processing your code actually does in this case is see if there is any data in the ring buffer, and if so read it out.
That process can be interrupted as needed, nothing there is super time critical, as the incoming data capture was already done by the hardware.

With a SW UART, whether written by you, or as provided by a Bascom instruction, it is running in the foreground.
The timing to read the incoming data bits is therefore important, and the presence of interrupts can disrupt the reading with respect to the Start Bit, thereby giving incorrect data.

Just putting a software UART command within an interrupt won't change anything.
When it fires, and your foreground code goes to read the SW UART pin, it is still a foreground process, and is subject to the same timing errors if any other ISRs are running.

JC
Back to top
View user's profile Visit poster's website
Paulvk

Bascom Member



Joined: 28 Jul 2006
Posts: 1257
Location: SYDNEY

australia.gif
PostPosted: Sun Jun 28, 2020 3:54 am    Post subject: Reply with quote

Hello JC
I thought that once you enter an interrupt other interrupts are stopped until you exit?
hence staying for short as possible in interrupts
Regards paul
Back to top
View user's profile
EDC

Bascom Expert



Joined: 26 Mar 2014
Posts: 971

poland.gif
PostPosted: Sun Jun 28, 2020 8:49 am    Post subject: Reply with quote

Why two Interrupts (Timer1 & Timer3) for the same period of time? They have the same values for reload...

Why not use Clear_Timer CTC mode for automatic reload?

Maybe even Interrupts for Timers are no necessarily...You can check flags of the Timers like that...

Code:
$regfile = "m1284pdef.dat"
$crystal = 9830400
$framesize = 800
$hwstack = 550                                              '
$swstack = 550



Config Timer1 = Timer , Prescale = 256 , Clear_timer = 1

Compare1a = 38399                                           '1000ms @ 9.8MHz/256

Do

 If Tifr1.ocf1a = 1 Then                            'Timer1InterruptsFlagsRegister.Timer1OnCompareAFlag
  Tifr1.ocf1a = 1                                           'clearing the flag by writing one into it


   Decr Wd_holdoffw
    toggle heartbeatLED
    if wd_holdoffw > 0 then
      dn20 = 0
      reset watchdog             'processor WD, set to 8sec. This is the only time in the whole code this happens
    else
      'the following code is very rarely if never . Causes system reset after 8 secs.
       print #1 , "WDHoldoff FAIL"
       if dn20 = 0 then Call Write_err_message( "WDHoldoff FAIL")       'write once only
       dn20 = 1
    end if


 End If

Loop


So Interrupts may be the smallest problem here Very Happy
Back to top
View user's profile Visit poster's website
JC

Bascom Member



Joined: 15 Dec 2007
Posts: 586
Location: Cleveland, OH

usa.gif
PostPosted: Sun Jun 28, 2020 3:47 pm    Post subject: Reply with quote

I must be having a bad week...

Paul, you are correct, that in the Megas and Tinies once you enter an interrupt the others are placed on hold.
(My excuse is that the last couple of projects I've done have used an Xmega, and with the 3-tiered interrupts that isn't the case.)
Sorry if I am giving you bad advice.

But hopefully it is helpful to carefully re-think the system!

JC
Back to top
View user's profile Visit poster's website
laborratte

Bascom Expert



Joined: 27 Jul 2005
Posts: 299
Location: Berlin

germany.gif
PostPosted: Tue Jun 30, 2020 4:52 pm    Post subject: Reply with quote

Just a thought:
In your loop
Code:
            Do
               Rxbyte = Inkey(#8)                              '#8 is pi sw uart ser port
               If Rxbyte <>0 Then
                  Tempstr7 = Tempstr7 + Chr(rxbyte)
               End If
            Loop Until Local_secl >= Td 'or rxbyte = 35         ' 35 = #  expected terminator  Td is time delay timeout.
 

your are concatenate strings (Tempstr7) whihch IMHO eats up more and more time as the string grows. Might be possible at >50 chars the time consumption is too high for your data stream and you are missing bits.

try to fill up a string overlay array with a pointer which schould be much faster.

[edit] if pi terminates every echo or data with <cr> you can easily use input instead of an inkey loop
Back to top
View user's profile
njepsen

Bascom Member



Joined: 13 Aug 2007
Posts: 469

newzealand.gif
PostPosted: Tue Jun 30, 2020 9:44 pm    Post subject: Reply with quote

Thanks Laborratte - I normally use a string array, but thought that building a string might be faster, alythough at 9600 i didnt think it would be a problem. . Easy to try. Yes there is a CR LF.
_________________
Neil
Back to top
View user's profile
AdrianJ

Bascom Expert



Joined: 16 Jan 2006
Posts: 2483
Location: Queensland

australia.gif
PostPosted: Wed Jul 01, 2020 1:30 am    Post subject: Reply with quote

Building strings from an array is good, but be aware that the string MUST end with a null ( chr(0) ) Else when you try and use the string somewhere else, you will get what looks like corruption, and very long strings.

My practice was always to insert the incoming character, then insert a null at the next location. That way you always have a terminating null, even if the transmission fails unexpectedly. The overhead of inserting 2 characters at each input is negligible.

One little-known trick with Bascom is to use the Mid function as an assignment:

Code:

if chrcount < maxlen 'check that the current chrcount is not longer than the string length assignment
Mid(tempstr,chrcount) = Rxbyte
end if
 

That inserts the Rxbyte directly into the string tempstr at the location pointed to by chrcount. And it even automagically converts the byte value to a character in the process.

So to insert the null, immediately following the Mid... statement, do

Code:

incr chrcount
Mid(tempstr,chrcount) = 0
 

_________________
Adrian Jansen
Computer language is a framework for creativity
Back to top
View user's profile Visit poster's website
EDC

Bascom Expert



Joined: 26 Mar 2014
Posts: 971

poland.gif
PostPosted: Wed Jul 01, 2020 1:49 am    Post subject: Reply with quote

Mark never said that you cannot watch MCS.LIB .. It is stated that this is prohibited to public anywhere else.
I like to read and learn from this lib (mcs.lib)
If string is expected then zero is inserted in the lib automatically Smile check me if Im wrong Razz
Back to top
View user's profile Visit poster's website
AdrianJ

Bascom Expert



Joined: 16 Jan 2006
Posts: 2483
Location: Queensland

australia.gif
PostPosted: Wed Jul 01, 2020 4:49 am    Post subject: Reply with quote

@EDC
Yes, if you concat a character on the end of a string, just by doing tempstr = tempstr + chr the null is inserted automatically. But last time I looked, if you use the Mid function to insert a character, it is not. Else you could not insert a character somewhere along an existing string without having it truncate after the insertion.

_________________
Adrian Jansen
Computer language is a framework for creativity
Back to top
View user's profile Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum