Shop OBEX P1 Docs P2 Docs Learn Events
Call method from ASM — Parallax Forums

Call method from ASM

soshimososhimo Posts: 215
edited 2010-07-17 23:46 in Propeller 1
I have a need to create some tight code to read from the serial port and place the data into one of two buffers. When the buffer gets to a certain size I want to switch buffers for the reader and signal a writer somewhere that a buffer of data is ready. The reader will be taking data from the FullDuplex object and the writer will be writing the data to an SD card.

My first attempt was in spin code. It worked, to a degree. If I put in a 500ms pause between each 16 byte writes I was able to get most of the data written to the card. I'm sure I had buffer overflows though as the number of bytes I actually read from the serial port was less than the number of bytes written and I made sure I flushed the output buffers from the client. That's still unacceptable, even without the data loss, as my maximum throughput will only ever be 32bytes / second. Pretty abysmal and not even worth using it for what I need it for.

My first thought was to drop down into ASM, but it's here where I ran I came to my first issue. How to call the methods on the fullduplex object declared in the OBJ section above? Is this possible? If so you can feel free to say RTFM, but just be so kind as to point out what page on TFM I can find this stuff [noparse]:)[/noparse].

TIA

Comments

  • LeonLeon Posts: 7,620
    edited 2010-07-17 07:31
    Can you use flow control, like XON/XOFF. to halt and restart the data?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Leon Heller
    Amateur radio callsign: G1HSM
  • soshimososhimo Posts: 215
    edited 2010-07-17 07:34
    Leon said...
    Can you use flow control, like XON/XOFF. to halt and restart the data?

    Wow, great idea. I'll give that a shot.

    Yeah, software flow control won't work - my data is binary. I could always go with hardware flow control but that requires two extra pins.

    Post Edited (soshimo) : 7/17/2010 7:39:42 AM GMT
  • LeonLeon Posts: 7,620
    edited 2010-07-17 09:27
    I think you will either have to use ASCII hex or use those two pins.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Leon Heller
    Amateur radio callsign: G1HSM
  • Cluso99Cluso99 Posts: 18,069
    edited 2010-07-17 11:01
    soshimo: yes it can be done. I posted a FDX object addition that increased the buffer sizes to miltiples of 2 to 256 (IIRC 512 fails). Now provided you do not have to stop the transmitter (i.e. you other cog can write the data quick enough) here is a suggestion...

    Modify my FDX object to use a 256 cyclic buffer (a single line constant). The second cog looks for when the buffer has 128 bytes (rx_head >= 128). When this happens it writes the 128 bytes to whereever and updates the rx_tail = 128 and then waits for next 128 bytes to fill. This is indicated by buffer wrap i.e rx_head < 128. When this happens it writes the buffer (upper 128 bytes) out and updates rx_tail = 0. The cycle continues.

    Hope this helps. IIRC my FDX is FullDuplexSerial_rr004.spin in the obex.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
    · Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
  • heaterheater Posts: 3,370
    edited 2010-07-17 11:42
    soshimo said...

    My first thought was to drop down into ASM, but it's here where I ran I came to my first issue. How to call the methods on the fullduplex object declared in the OBJ section above? Is this possible? If so you can feel free to say RTFM, but just be so kind as to point out what page on TFM I can find this stuff [noparse]:)[/noparse].

    Thing is you don't have to call any spin methods from your asm to use FullDuplexSerial or many other objects. In fact it's not possible.

    FullDuplex serial runs it's serious business as PASM in a COG. As such it interfaces to the rest of the system through transmit and receive buffers in HUB together with a couple of pointers into each of those buffers, also in HUB.

    Those Spin methods that you normally call to use FullDuplexSerial ".tx" ".rx" etc just put data into or get data out of those buffers in HUB. And then update the pointers appropriately. The FullDuplexSerial cog then sees the pointers have moved and can then put data into or remove data from the buffers.

    This means that your PASM code running it's own cog can do likewise, just accessing the FDX buffers and pointers in HUB, to send and receive data.

    The only problem remaining is how to tell your PASM code where those FDX buffers and pointers are in HUB. This is best done by passing a pointer through PAR.

    Luckily the Spin code in FullDuplexSerial is not necessary to actually use it. That way I can use the FDX PASM part from C++ with Zog. This is true of a lot of objects that you can find.

    Bill Henning is on a crusade to get people to use this approach for all objects such that they can be used from any language just by reading and writing to "mailboxes" in HUB. It's a kind of "remote procedure call" if you like.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Dave HeinDave Hein Posts: 6,347
    edited 2010-07-17 12:37
    It seems like you should be able to handle a fairly high speed without losing data if you use 3 cog.· One cog runs FDS, another cog runs the SPI code to talk to the SD card and the third cog runs the buffering scheme.· The key is to ensure that the third cog never sits in a tight loop waiting on either of the other two cogs.

    The polling loop should check for data from FDS, and transfer that to one of the ping-pong buffers.· If there is no FDS data, the polling loop should then check on the status of an SD write operation that may be in progress.· With this method you should be able to handle a fairly high speed using Spin -- maybe 57,600 baud.· You may need to use a ring buffer instead of just a simple ping-pong buffer.· I don't have much experience writing at high speeds to an SD card, but I think there will be stalls sometimes.

    Dave
  • soshimososhimo Posts: 215
    edited 2010-07-17 22:31
    Dave Hein said...
    It seems like you should be able to handle a fairly high speed without losing data if you use 3 cog. One cog runs FDS, another cog runs the SPI code to talk to the SD card and the third cog runs the buffering scheme. The key is to ensure that the third cog never sits in a tight loop waiting on either of the other two cogs.

    The polling loop should check for data from FDS, and transfer that to one of the ping-pong buffers. If there is no FDS data, the polling loop should then check on the status of an SD write operation that may be in progress. With this method you should be able to handle a fairly high speed using Spin -- maybe 57,600 baud. You may need to use a ring buffer instead of just a simple ping-pong buffer. I don't have much experience writing at high speeds to an SD card, but I think there will be stalls sometimes.

    Dave

    I'm definitely going to implement this but I decided to give the hardware handshaking a test. I was able to get decent results at 9600 buad. Anything higher and I started to lose data. So basically I have a tight loop that searches for BLOCKSIZE (or remaining if remaining is less than BLOCKSIZE) bytes from the stream. I know how many bytes I am expecting because the client sends that data before sending the file data. Once I get BLOCKSIZE bytes from the stream I bring the CTS pin high. This tells the transmitter to stop sending data (which blocks my client program, but that's expected). I then write that buffer to the file by calling pwrite on the fsrw object. I then bring CTS back low, this signals the transmitter that all is well and it will start transmitting again. At this point I enter my tight loop waiting for data, or exit if no data is remaining.

    I've experimented with BLOCKSIZE and whether it's a function of my client transmit buffer size and/or the FDS rx buffer size I don't know, but the sweet spot seems to be 1024 bytes.

    The fact that I have to play with "magic numbers" makes me think it's too rube goldberg'ish so I will be investigating the solution you proposed above.
  • Dave HeinDave Hein Posts: 6,347
    edited 2010-07-17 23:46
    A tight Spin loop that calls fds.rx and then stores the result in a byte array runs between 57,600 and 115,200 baud.· I don't remember the exact speed.· If you do anything else in that loop it will run even slower.· I did run a few tests with FDS where I added a block-read method.· This was able to run over 1 mbps, and it was still using Spin.

    The standard FDS receiver buffer is only 16 bytes.· The sender has to react quickly enough to the hardware flow control to stop within 16 bytes.· You may need to increase the receive buffer to operate at higher speeds.

    I assumed you were writing directly to the SD card.· If you use pwrite in FSRW it will block while it is writing to the SD card.· Your hardware flow control will keep the sender from transmitting during this time.· If you want to operate without flow control you would need to make the block write non-blocking.· You could do this by using an additional cog.· So there would be four cogs total.· There would be one for the polling loop, another for FDS, another for FSRW and a fourth one for the SPI driver.

    Dave
Sign In or Register to comment.