Shop OBEX P1 Docs P2 Docs Learn Events
Communicating with Serial in .cogc routine — Parallax Forums

Communicating with Serial in .cogc routine

onecsguyonecsguy Posts: 2
edited 2013-04-03 07:38 in Propeller 1
Problem:
Need to communicate over serial from a cogc routine as my main cog is running blocking (TCP/IP) routines and the serial communication needs to be as close to realtime as possible.
Having trouble including simple serial driver in cogc as the linker doesn't know to put simple serial driver in lower cog addressable memory for the cogc file.
Compiling with XMCC using an SD card for cache on the Spineret server board.
I have tried several approaches, one approach was to bring all of the simple serial code into the .cogc file, but then I have linker errors about CLKFREQ being outside of cog addressable memory.

Use Case:
What I am trying to do is communicate in the main cog with a web server, and have a secondary cog communicate with a serial peripheral for live movement control.

Environment:
Tried in both SimpleIDE & with custom Makefile

In Summary:
How can I write/compile code for a .cogc routine that shares routines such as simple serial or time operations such as wait_cnt when the main cog uses XMCC code caching. How to I either force the compiler to keep shared routines in lower memory, or write better cogc code.
I have various errors depending on my approach but I was wondering if anyone has written a large main cog program with small cogc routines. The cog_loader demo in the documentation is a small program with cogc routines which doesn't have any memory issues since the entire program fits in cog memory.

If anyone has experience or sample code for something like this help would be appreciated.

Thanks

Comments

  • ersmithersmith Posts: 6,054
    edited 2013-04-02 12:49
    Your .cogc program has to entirely fit in a COG, i.e. it must be < 2K. That means you can't do very much with it, but serial I/O is certainly a possibility. Serial output on one pin is easy -- just change _txpin to whatever pin you want, and use putchar() (the source code for this is in http://code.google.com/p/propgcc/source/browse/lib/cog/cogserial.c). To do serial input you'll have to adapt the code from simple_serial. There shouldn't be any issue with CLKFREQ, since that is in hub memory (I assume you are using XMMC mode and not XMM -- using XMM will be very difficult, since all data is then in external memory).

    Another possibility would be to use the FullDuplexSerial driver running in another COG. Again, you'd have to adapt the interface code for your .cogc files.

    Eric
  • onecsguyonecsguy Posts: 2
    edited 2013-04-03 07:38
    ersmith wrote: »
    Your .cogc program has to entirely fit in a COG, i.e. it must be < 2K. That means you can't do very much with it, but serial I/O is certainly a possibility. Serial output on one pin is easy -- just change _txpin to whatever pin you want, and use putchar() (the source code for this is in http://code.google.com/p/propgcc/source/browse/lib/cog/cogserial.c). To do serial input you'll have to adapt the code from simple_serial. There shouldn't be any issue with CLKFREQ, since that is in hub memory (I assume you are using XMMC mode and not XMM -- using XMM will be very difficult, since all data is then in external memory).

    Another possibility would be to use the FullDuplexSerial driver running in another COG. Again, you'd have to adapt the interface code for your .cogc files.

    Eric

    Eric, Thank you for your reply, that is very helpful information.

    I am using XMMC

    The simple serial re-write approach is what I have been using, I have been calling my version MicroSerial and removing the overhead of stream driver compatibility. just simply: micro_open, micro_putbyte, micro_getbyte, micro_close

    I have tried this in a .h file and also including within the cogc file with issues around the "__builtin_propeller_waitcnt" and similar functions from functions found in <propeller.h>

    **UNTESTED CODE EXCERPT**
    unsigned int micro_setup[4];
    
    __attribute__((fcache))
    static int
    micro_putbyte(int c)
    {
      unsigned int txmask = micro_setup[1];
      unsigned int bitcycles = micro_setup[3];
      unsigned int waitcycles;
      int i, value;
    
      /* set input */
      _OUTA |= txmask;
      _DIRA |= txmask;
    
      value = (c | 256) << 1;
      waitcycles = _CNT + bitcycles;
      for (i = 0; i < 10; i++)
        {
          waitcycles = __builtin_propeller_waitcnt(waitcycles, bitcycles);
          if (value & 1)
        _OUTA |= txmask;
          else
        _OUTA &= ~txmask;
          value >>= 1;
        }
      return c;
    }
    
    __attribute__((fcache))
    static int
    micro_getbyte()
    {
      unsigned int rxmask = micro_setup[0];
      unsigned int bitcycles = micro_setup[3];
      unsigned int waitcycles;
      int value;
      int i;
    
      /* set input */
      _DIRA &= ~rxmask;
    
      /* wait for a start bit */
      if (1) {
        /* if non-blocking I/O, return immediately if no data */
        if ( 0 != (_INA & rxmask) )
          return -1;
      } else {
        __builtin_propeller_waitpeq(0, rxmask);
      }
      /* sync for one half bit */
      waitcycles = _CNT + (bitcycles>>1) + bitcycles;
      value = 0;
      for (i = 0; i < 8; i++) {
        waitcycles = __builtin_propeller_waitcnt(waitcycles, bitcycles);
        value = ( (0 != (_INA & rxmask)) << 7) | (value >> 1);
      }
      /* wait for the line to go high (as it will when the stop bit arrives) */
      __builtin_propeller_waitpeq(rxmask, rxmask);
      return value;
    }
    
    static int micro_open(unsigned int rxpin, unsigned int txpin, unsigned int baud)
    {
      unsigned int bitcycles;
    
      bitcycles = _clkfreq / baud;
    
      /* set up the array */
      micro_setup[0] = (1U<<rxpin);
      micro_setup[1] = (1U<<txpin);
      micro_setup[2] = baud;
      micro_setup[3] = bitcycles;
    
      /* mark it as being a terminal */
      //fp->_flag |= _IODEV;
    
      /* all OK */
      return 0;
    }
    
    static void micro_close(void)
    {
      _OUTA |= (1<<micro_setup[0]);
      _DIRA |= (1<<micro_setup[1]);
    }
    


    However, I am plagued with compilation errors because it seems the linker or .text copy routine is putting the shared symbols referenced in propeller.h "including CLKFREQ" which are required for accurate serial timing into memory that is inaccessible from cogc programs and I receive a relocation truncated to fit .text error. I will be able to post the exact errors once I get my compiler running again after breaking it while setting my path so I could use make instead of SimpleIDE.

    Now as far as communicating with a FullDuplexSerial cog, I have been thinking about that, then it is just a shared memory based interface? But simple serial was easier for me to understand and it *should* work in a cog as I have written it.


    Brant
Sign In or Register to comment.