Shop OBEX P1 Docs P2 Docs Learn Events
Spin2 Serial I/O for both Fastspin and Pnut? — Parallax Forums

Spin2 Serial I/O for both Fastspin and Pnut?

What options are there for serial I/O that works with both FastSpin and Pnut?

I've been using SmartSerial, but I'm pretty sure that won't work with Pnut…

I think there's fullduplexserial around somewhere...

Is there anything that doesn't use a cog?

Comments

  • ElectrodudeElectrodude Posts: 1,657
    edited 2020-05-19 16:40
    I don't bother using any special serial driver or library on the P2, since it's so easy to do it with plain old smartpins. It's like asking for a special library to blink an LED - it's much less work and less overhead to just blink it yourself directly on a timer you manage.
  • RaymanRayman Posts: 14,646
    I just remembered that @JonnyMac posted a serial driver...
    Found in this thread: http://forums.parallax.com/discussion/171327/p2-tm1638-driver-and-demo#latest

    Did a quick look at jm_serial.spin2 and it looks like just what I want. Well, maybe a little more than I need, but that's probably OK.
  • Reminder: It's not FDS, I did it so that I could have nice formatting to the terminal as I am working with the P2. The formatting code is in its own object so that it can be used with any serial output device.
  • I think it's really time to start putting library code into OBEX (GITHUB). There's so much code out there but nobody finds it because it's distributed in the forum and the search function is not very good.

    I've been there... I've written just another SPI driver because it was easier to code some than to search and ask.

    Of course releasing code to the public is much work. You need to carefully test and document it and be prepared for questions. But I think even a "raw" piece of code (I mean not very well tested and documented) would be helpful. At least everybody could see that there is already something and it's not necessary to re-invent the wheel. If there is a lot of interest the author could improve documentation and fix bugs later. If not nothing is lost.
  • Cluso99Cluso99 Posts: 18,069
    Ray,
    My Serial Monitor compiles in both fastspin and pnut. It’s really a serial library but you can also call it as a monitor too. It also supports a cog/lut/hub list (dump) call in addition to the usual char, string, hex, etc routines.
    For compiling it with fastspin, you just need to change the cog base _reg to $000 instead of $120 that I use in pnut.

    The only thing that it doesn’t do is receive by interrupt. It has receive chat, string, check, and peek.

    The send and the receive routines all come down to two tiny calls permitting easy modifications if required. I will probably add an interrupt call option to change to receive under interrupts later.

    It’s working really well for me now. It’s based on my serial monitor in the P2 ROM, plus a few additions.
  • ManAtWork wrote: »
    I think it's really time to start putting library code into OBEX (GITHUB). There's so much code out there but nobody finds it because it's distributed in the forum and the search function is not very good.

    I've been there... I've written just another SPI driver because it was easier to code some than to search and ask.

    Of course releasing code to the public is much work. You need to carefully test and document it and be prepared for questions. But I think even a "raw" piece of code (I mean not very well tested and documented) would be helpful. At least everybody could see that there is already something and it's not necessary to re-invent the wheel. If there is a lot of interest the author could improve documentation and fix bugs later. If not nothing is lost.

    For a new user like myself, this would be very helpful indeed. Yes, I've found things by searching and then reading the entire text of the resultant threads, some many years old but so full of shared knowledge. Having a go to place for drivers and examples is the one thing that would make this so much easier, not to supplant the forum search, but to enhance the overall user experience.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-05-20 01:45
    FDS is not rocket science. Personally I prefer to have receive interrupts for buffering but transmit direct from the smartpin, especially if you check for empty first, then send, which means you are only delaying because your output is faster than the baudrate. Oftentimes, direct is much faster than buffering and send, plus unless the transmit buffer is large enough, it will still end up blocking at low baud rates anyway. This is also a very good reason to have a fast baudrate so that in TAQOZ even at 8Mbd I can download and compile source.

    If no one else writes an object, I'm sure I could quickly write some Spin2 code to do this or do I have to say "it's impossible" :)
  • RaymanRayman Posts: 14,646
    edited 2020-05-20 02:01
    One nice thing about @JonnyMac's code is that, like "SmartSerial", it doesn't use a cog.
    If this could be done with interrupts too, so as to include buffering, that might be interesting...
    Not sure it would be possible for the same code to compile with both PNut and Fastspin…

    So far, I haven't seem to have needed buffering. But, I'm sure there will be a case where I do...
  • Rayman wrote: »
    So far, I haven't seem to have needed buffering. But, I'm sure there will be a case where I do...

    You may potentially require buffering if you paste data into a terminal and send to a prop. I found this with Micropython for example and added some receive buffering in the LUTRAM with an interrupt driven receiver in the main COG.

    Just interactively typing directly into a terminal is often slow enough that a receiver can keep up (depending on what it does to parse and act on the data received).
  • Cluso99Cluso99 Posts: 18,069
    edited 2020-05-20 03:00
    FDS is not rocket science. Personally I prefer to have receive interrupts for buffering but transmit direct from the smartpin, especially if you check for empty first, then send, which means you are only delaying because your output is faster than the baudrate. Oftentimes, direct is much faster than buffering and send, plus unless the transmit buffer is large enough, it will still end up blocking at low baud rates anyway. This is also a very good reason to have a fast baudrate so that in TAQOZ even at 8Mbd I can download and compile source.

    If no one else writes an object, I'm sure I could quickly write some Spin2 code to do this or do I have to say "it's impossible" :)

    How many times do I need to say it...

    My Serial Monitor is a serial handler that does not use up a cog, resides in hub as hubexec (which incidentally overwrites my ROM Monitor and uses the very same calls and locations as the ROM - although that may change) and uses 16 cog long variables which are reconfigurable to suit pnut or fastspin. It comes complete with the ability to be called from spin or asm, and you can also call into the monitor to look and change cog/lut/hub and then return to your program with the "Q" command.
    It's FDX on steroids with one current exception - it's half duplex as I don't use interrupts to receive characters or strings. I do plan to add an option to use receive via interrupts shortly.

    Have you ever wanted to dump memory like this...
    cog...
      100: DE 0A 00 00  DF 02 00 00  E4 1A 00 00  E4 BA 3F 00   '..............?.'
      104: E4 7A 00 00  E4 FA 3E 00  E4 FA 01 00  E4 BA 03 00   '.z....>.........'
    hub...
    01040: 3A 3A 3A 3A  3A 3A 3A 3A  3A 3A 3A 3A  3A 3A 3A 3A   '::::::::::::::::'
    01050: 41 20 74 65  73 74 20 73  74 72 69 6E  67 0A 0D 00   'A test string...'
    
    It is now as simple as doing this in your code...
    spin2...
        ser.DumpMem($100, $110)                             ' dump memory byte cog $100-$110     (f=List+Addr2)
        ser.DumpMem($01040, $01080)                         ' dump memory byte hub $01040-$01080 (f=List+Addr2)
    pasm...
                mov         mon.p,            ##$1_00100
                mov         mon.p2,           ##$1_00140
                call        #\mon.TxListA2                  ' print list hub $00100-$00140 (f=List+Addr2)
    

    PS I'm using it in my P2 OS and it runs fine :)
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-05-20 03:25
    @Cluso99 - I'm talking about interrupt driven receive which is always important. Even my TAQOZ in ROM has interrupt driven rx running. Polling the smartpin for rx data is just wishful thinking. There are plenty of examples out there with interrupt driven rx and I know my stuff works even at 12Mbd rx, even if the USB chip can't handle the 12Mbd back :)

  • Here's a demo of a interrupt driven serial receiver in the same cog as the SPIN2 interpreter.
    {
    Buffered serial receiver - ozpropdev 2020
    }
    COM
    
    	_clkfreq = 180_000_000
    	config = (_clkfreq / 115_200) << 16 | 7
    	rx = 63
    	tx = 62
    
    pub main()
    
    	pinstart(rx,p_async_rx,config,0)
    	pinstart(tx,p_async_tx + p_tt_01,config,0)
    	send := @tx_byte
    
    	pr0 := @rx_isr			'get isr address
    	pr2 := @buffer			'get buffer address
    	pr3~				'index_in
    	pr4~				'index_out
    
    	org
    	mov	ijmp1,pr0		'set isr address
    	setse1	#%001_000000 | rx	'trigger on pin rise
    	setint1	#4			'se1 interrupt
    	end
    
    	repeat
    		waitms(5000)		'waste some time
    		pint(56)		'toggle led
    
    		repeat while pr3 <> pr4	'empty buffer
    			send(byte[@buffer][pr4++])
    			pr4 &= $ff
    
    pub tx_byte(c)
    
    		org
    txw		rdpin	ina,#tx wc
    	if_c	jmp	#txw
    		wypin	c,#tx
    		end
    	
    dat		orgh
    
    rx_isr		rdpin	pr0,#rx		'get rx data
    		getbyte	pr0,pr0,#3	'get char
    		mov	pr1,pr2		'buffer start
    		add	pr1,pr3		'add index_in
    		wrbyte	pr0,pr1		'save char
    		incmod	pr3,#255	'adjust and wrap index
    		reti1			'interrupt return
    
    buffer		byte	0[256]
    
    
    
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-05-20 04:20
    @ozpropdev - your sample code could do with the buffer read part as well since I noticed that you are only updating an index in a cog register and you need a copy of that in hub (unless the rxbuf read is also in cog, or hubexec i guess). Isn't your getbyte just another way of saying shr pr0,#24?
  • @"Peter Jakacki"
    Yes the GETBYTE does the same thing as SHR #24.
    The PR0..PR7 registers are reserved cog registers directly accessable from Spin2.
    Here's an updated source with rx_check and rx_read. :)
    {
    Buffered serial receiver - ozpropdev 2020 V2
    }
    COM
    
    	_clkfreq = 180_000_000
    	config = (_clkfreq / 115_200) << 16 | 7
    	rx = 63
    	tx = 62
    
    pub main()
    
    	pinstart(rx,p_async_rx,config,0)
    	pinstart(tx,p_async_tx + p_tt_01,config,0)
    	send := @tx_byte
    
    	pr0 := @rx_isr			'get isr address
    	pr2 := @buffer			'get buffer address
    	pr3~				'index_in
    	pr4~				'index_out
    
    	org
    	mov	ijmp1,pr0		'set isr address
    	setse1	#%001_000000 | rx	'trigger on pin rise
    	setint1	#4			'se1 interrupt
    	end
    
    	repeat
    		waitms(5000)		'waste some time
    		pint(56)		'toggle led
    
    		repeat while rx_check()	'repeat until empty buffer
    			send(rx_read())
    
    pub rx_read():char
    
    	char := byte[@buffer][pr4++]
    	pr4 &= $ff
    
    pub rx_check():available
    
    	return (pr3 <> pr4)
    
    pub tx_byte(c)
    
    		org
    txw		rdpin	ina,#tx wc
    	if_c	jmp	#txw
    		wypin	c,#tx
    		end
    	
    dat		orgh
    
    rx_isr		rdpin	pr0,#rx		'get rx data
    		getbyte	pr0,pr0,#3	'get char
    		mov	pr1,pr2		'buffer start
    		add	pr1,pr3		'add index_in
    		wrbyte	pr0,pr1		'save char
    		incmod	pr3,#255	'adjust and wrap index
    		reti1			'interrupt return
    
    buffer		byte	0[256]
    
    
    
  • Cluso99Cluso99 Posts: 18,069
    edited 2020-05-20 06:11
    @Cluso99 - I'm talking about interrupt driven receive which is always important. Even my TAQOZ in ROM has interrupt driven rx running. Polling the smartpin for rx data is just wishful thinking. There are plenty of examples out there with interrupt driven rx and I know my stuff works even at 12Mbd rx, even if the USB chip can't handle the 12Mbd back :)
    Yes, I know Peter. And I pretty much agree...

    BUT some programs will not be able to cater for interrupt driven receive. For example, when reading/writing SD or Flash. There is also the case for a user running spin programs which may not be aware of what interrupts will do to his/her code.

    So, there is a case for both. And that is what I will be doing. It will also be possible to have the serial in it's own cog where interrupts will not matter for the users code.

    And as you know, most code is really half duplex. It sends something out, waits for a response or new data, processes it and sends something out again. Rinse and repeat.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-05-20 07:13
    I would suggest then that a cog be dedicated for system functions such as serial interrupt buffering, background timers, time of day, and other services. That way it would be much simpler to load the binary for the services cog and run it without having to know too much, it would be language agnostic. Mailboxes will do the rest.

    (I think I can do that myself, just a binary blob that any language can shove into a cog.)
  • RaymanRayman Posts: 14,646
    I think/hope there is some instruction that blocks interrupts in critical areas
  • Ahle2Ahle2 Posts: 1,179
    Rayman,

    I think STALLI/ALLOWI is what you are looking for!
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-05-20 11:53
    Well, what if we do have these binary blobs, or ROMs I called them on the P1 which are loaded into a cog. I had serial, and VGA, SIDCOG and F32 etc loaded in from upper EEPROM into the cog.

    Can we load binary files easily in all the different ways of developing code? It would be like a preprogrammed chip, which it is, that doesn't need anything else except the mailboxes in low hub perhaps. Serial buffers could be maintained in LUT and surely we could have the one cog handle more than one serial channel. Same applies for other functions. Each cog should have a reserved mailbox area that could even point to new mailboxes.

    This ROM could have 4 FDS serial ports or more, timer functions, time of day etc. I find that with a hardware RTC that it is easier to read this only once every so often and maintain the time in a more conducive format in software with very fast access, especially for time stamps.
Sign In or Register to comment.