Serial pass-through application.

Discussion about the ZBasic language including the System Library. If you're not sure where to post your message, do it here. However, do not make test posts here; that's the purpose of the Sandbox.
Post Reply
cerickson
Posts: 45
Joined: 20 May 2008, 15:50 PM
Location: Waikoloa Village, HI, USA
Contact:

Serial pass-through application.

Post by cerickson »

Hello all,

I am new to Zbasic and a bit new to microcontrollers in general. I played with the Parallax BS2p stamp long enough to figure out that it probably didn't have the horsepower I needed. After some researching I found the Zbasic microcontrollers and here I am!

In a nutshell, my application is as follows:

A box with two serial ports. It is a pass-through device that sits silently in the middle of a 9600 baud, 8 bit, no parity, 1 stop bit, no handshaking conversation between two existing legacy serial devices. Communications activity between the two devices is relatively low. Maybe one to thirty 4-80 character strings per minute, terminated by CR's. The box will receive ASCII strings from either end, buffer them until a CR is received and then forward them out the other port when it is determined to be idle.

About once a minute, the box will start queueing up any data received on port A and send a special command out port B. It will then (hopefully) receive a reply on port B. It will then send any data queued up from port A to port B, adding a .5 second or so delay after every CR in the buffered data. It will be important that no data is lost between the two ports and that the box's presence is effectively invisible from the perspective of the two legacy devices connected to the two ports. The box will take the information it received via it's request to and reply from port B and after a series of logic decisions, control two reversible gearhead 12VDC motors via relays. The box will also have a small LCD screen and four pushbuttons that will be used to configure various settings in the box. All of these other functions are relatively insensitive to timing issues. There will be a number of other digital inputs and outputs that will interact with the real world but will also be relatively insensitive to timing issues.

I really want to stick to a microcontroller development platform with a higher level language. I have never had joy working with C or assembler on PC platforms in the past. Way too many housekeeping chores and subtle, hard to squash bugs to track down for my taste.

My questions are as follows:

1. Would the ZX-24P and its two hardware serial ports be a good choice for this application?

2. Would it be fast enough to not ever lose any of the serial data?

3. Would the Zbasic interrupt and multitasking capabilities, etc. make it a better choice for this application than any of the other high level language microcontroller platforms out there?

4. What problems would you anticipate?

5. Would the ZX-24n be required to get the performance needed?

6. Would anyone have any code samples that might be appropriate for this application and would they be willing to share them?

Thanks in advance for any and all replies,

-Christopher Erickson
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: Serial pass-through application.

Post by dkinzer »

cerickson wrote:1. Would the ZX-24P and its two hardware serial ports be a good choice for this application?
The ZX-24P (or any of the mega644P-based devices) would be a good choice. However, based on your description of the required functionality I believe that any ZX device would be able to handle it using 1 hardware and 1 software serial port. In fact, it may work best to reserve Com1 for debugging and use Com2 (if available) and Com3 for the pass-through ports.
cerickson wrote:2. Would it be fast enough to not ever lose any of the serial data?
The key will be to have queues that are large enough to accommodate the maximum message size. Depending on the spacing of the messages, you may need room in the receive queue for 1.5 to 2 messages. Some analysis of the message timing and processing time will lead you to the desired size.

Depending on the format of the messages, you may be able to get by with much smaller queue sizes, immediately passing characters from the receive queue to the transmit queue and keeping track of the what has passed using a state machine and some auxiliary variables. If you're not familiar with the concept of a state machine, see the Wikipedia article on finite state machines for some background information.
cerickson wrote:5. Would the ZX-24n be required to get the performance needed?
I suspect that the VM-mode devices would work fine based on your description.
- Don Kinzer
cerickson
Posts: 45
Joined: 20 May 2008, 15:50 PM
Location: Waikoloa Village, HI, USA
Contact:

Re: Serial pass-through application.

Post by cerickson »

So I should set up interrupts to watch the two serial ports and pull the data from the two interfaces a byte at a time or should I set up some kind of polling or some kind of multitasking approach?

I apologize for my current lack of experience with Zbasic. This is a BIG learning curve from Pbasic and I can't find a good Zbasic tutorial anywhere to get myself up to speed.

Is there some sample code someplace that deals with two serial ports in a similar fashion that I could study?

I am even having trouble confirming what pins are dedicated to the second hardware UART in the ZX-24P. Is there a "main document" I am overlooking someplace?

Thanks in advance,

-Christropher Erickson
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Re: Serial pass-through application.

Post by dkinzer »

cerickson wrote:So I should set up interrupts to watch the two serial ports [...]
ZBasic provides a mechanism - queues - for collecting characters received from serial ports and for managing characters to be sent out a serial port. All that is necessary is to define the queues, initialize them, and then associate them with the serial port. Each serial port needs its own transmit and/or receive queue (it is possible to have send-only or receive-only serial ports by associating only a transmit or a receive queue, respectively).
cerickson wrote:Is there some sample code someplace that deals with two serial ports in a similar fashion that I could study?
Take a look at the sample code below. It defines a pair of queues (iq2 and oq2), initializes them with calls to OpenQueue() and then opens Com2 specifying those queues. Com1 is opened automatically so nothing needs to be done with that unless you need larger than the default queue sizes.

Following the initialization, the main loop consists of two sub-loops, each of which reads from one port's receive queue (if it has data available) and transfers the data to the other port's transmit queue. If you wire up the ZX on a prototyping board with RS-232 level converters connected to Com2's Rx and Tx lines and then connect a terminal to Com1 and Com2, you can type on one and see the result on the other. (You can use a PC-based terminal emulator like TeraTerm or Bray Terminal for this purpose.)

Code: Select all

Const qsize as Byte = 20
Private iq2(1 to qsize) as Byte
Private oq2(1 to qsize) as Byte

Sub Main()
  Call OpenQueue(iq2, SizeOf(iq2))
  Call OpenQueue(oq2, SizeOf(oq2))
  Call OpenCom(2, 19200, iq2, oq2)
  Debug.Print "Hello, world!"
  Call PutQueueStr(oq2, "Hello, world!" & Chr(&H0d) & Chr(&H0a))
  Do
    Dim c as Byte
    Do While &#40;GetQueueCount&#40;iq2&#41; <> 0&#41;
      Call GetQueue&#40;iq2, c, 1&#41;
      Call PutQueueByte&#40;CByteArray&#40;Register.TxQueue&#41;, c&#41;
    Loop
    Do While &#40;GetQueueCount&#40;CByteArray&#40;Register.RxQueue&#41;&#41; <> 0&#41;
      Call GetQueue&#40;CByteArray&#40;Register.RxQueue&#41;, c, 1&#41;
      Call PutQueueByte&#40;oq2, c&#41;
    Loop
  Loop
End Sub
cerickson wrote:I am even having trouble confirming what pins are dedicated to the second hardware UART in the ZX-24P. Is there a "main document" I am overlooking someplace?
Ultimately, the information that you seek can be deduced by consulting the Atmel datasheet for the underlying processor (ATmega644P) and the schematic for the ZX-24P. These two documents are the ultimate source for many kinds of information. That said, the pins used for each hardware serial port are listed in the Resources section of the ZBasic System Library Manual. Note the the terms transmit and receive are used with respect to the UART itself so the Tx line is an output and the Rx line is an input.

One thing to note about the example code above is that the form used there, two loops in series, may not be best for a particular application. It might be better to replace each of the inner loops with an If statement so that only one received character gets processed on each pass. The main loop would then look something like this:

Code: Select all

  Do
    Dim c as Byte
    If &#40;GetQueueCount&#40;iq2&#41; <> 0&#41; Then
      Call GetQueue&#40;iq2, c, 1&#41;
      Call PutQueueByte&#40;CByteArray&#40;Register.TxQueue&#41;, c&#41;
    End If
    If &#40;GetQueueCount&#40;CByteArray&#40;Register.RxQueue&#41;&#41; <> 0&#41; Then
      Call GetQueue&#40;CByteArray&#40;Register.RxQueue&#41;, c, 1&#41;
      Call PutQueueByte&#40;oq2, c&#41;
    End If
  Loop
- Don Kinzer
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post by dkinzer »

I probably should have said more in my last post about the construction CByteArray(Register.TxQueue) and the similar construction using Register.RxQueue. These constructions are a way to refer to the default queues for Com1, the equivalent of referring to oq2 and iq2 for Com2.

Although perhaps a more advanced topic, you can used the Based variable capability of ZBasic to simplify the references to the default Com1 queues. Consider these definitions:

Code: Select all

Dim iq1&#40;&#41; as Byte Based Register.RxQueue
Dim oq1&#40;&#41; as Byte Based Register.TxQueue
Once these definitions are made, you can refer to the default input and output queues for Com1 using iq1 and oq1 in place of the longer CByteArray(Register.RxQueue) and CByteArray(Register.TxQueue) as in the rewritten example code below.

Code: Select all

Private iq1&#40;&#41; as Byte Based Register.RxQueue
Private oq1&#40;&#41; as Byte Based Register.TxQueue

Const qsize as Byte = 20
Private iq2&#40;1 to qsize&#41; as Byte
Private oq2&#40;1 to qsize&#41; as Byte

Sub Main&#40;&#41;
  Call OpenQueue&#40;iq2, SizeOf&#40;iq2&#41;&#41;
  Call OpenQueue&#40;oq2, SizeOf&#40;oq2&#41;&#41;
  Call OpenCom&#40;2, 19200, iq2, oq2&#41;
  Debug.Print "Hello, world!"
  Call PutQueueStr&#40;oq2, "Hello, world!" & Chr&#40;&H0d&#41; & Chr&#40;&H0a&#41;&#41;
  Do
    Dim c as Byte
    Do While &#40;GetQueueCount&#40;iq2&#41; <> 0&#41;
      Call GetQueue&#40;iq2, c, 1&#41;
      Call PutQueueByte&#40;oq1, c&#41;
    Loop
    Do While &#40;GetQueueCount&#40;iq1&#41; <> 0&#41;
      Call GetQueue&#40;iq1, c, 1&#41;
      Call PutQueueByte&#40;oq2, c&#41;
    Loop
  Loop
End Sub
- Don Kinzer
Post Reply