"Inline" Asynchronous Serial Driver (Yet Another) [Library]
Figure I'd share my "inline" asynchronous serial library and other various libraries that I have been working on. This is mainly a 'reinvent the wheel' type of project, being my first project beyond blinking and LED so I can get a handle on Spin2 and PASM2 as I get familiar with the P2.
I've seen simpler, and more complex libraries that essentially do the same. I can't say that mine is unique in any way since I didn't dig too deep in the various libraries mostly spread through this forum. There are a few interesting features though which may give it a leg up in some situations.
This is the project that dug up the Spin2 documentation error which the thread is here.
Source
The source is located on Github here. The file in focus is piInlineSerial.spin2. The following is a hierarchal drawing of the library with the terminal library as the top object to give sense of organization:
Serial Library Info:
Features
- Follows Single-Responsibility Principle
- doesn't include string-formatting for example, that is located in a standalone library that can be utilized with any other output/stream library by utilizing send/recv hooks.
- "Zero cog" asynchronous tx/rx buffer handling
- resides in the user-assembly section of the cog spared by the Spin2 interpreter
- due to this, inline PASM is not allowed when utilizing this serial library
- Supports None, Even, and Odd Parity
- Supports 1 or 2 Stop Bits
- Parity, Framing, and Overflow Error Handling and Status Flags
- Read/Write Functions with Timeout Support (Immediate and Infinite)
- Full Density Transmit/Receive
- no dead time between bytes with typical clock/baudrate settings (20MHz, 115k)
- Lightweight... It exists in the first $124 longs of the cog
Missing Functionality
- Flushing
- TXEN Functionality
- I want to try to use the 3rd interrupt on a counter-passed event to time it accurately right after the last byte write since there is no tx shifter empty interrupt.
I decided not to support non 8-bit data... it would have complicated things too much.
Comments
Demos
Demo_piInlineSerial
Illustrates the error catching mechanisms that are part of the serial library.
Demo Output
Demo_piTerminal
Provides an example terminal-like interface with a few example commands such as stack, cogs, stop, and help.
Demo Output
'>' replaced by '$' due to forum interpreting as tag
Personal Observations
Objectives
Things Learned / Dislikes
Transmit Interrupt Timing
I found it difficult to perfect the transmit section of the code. There is a ton of edge cases. What if we try to write more data than the buffer allows? What if the baudrate sends data faster than we fill the buffer? What if we send slower?
I had to do a weird critical section in write_asm where I would prevent interrupts for a few cycles to let the input buffers "catch up". I learned late in the game that perfect timing was happening where the interrupt was returning at the perfect moment that IN was being assert between the IN-check and triggering an interrupt.
PropTool doesn't support folders for OBJ instances
This breaks any clean way to use version control on libraries. Normally I would heavily use git submodules to separate my own library/application code and to use other user's code. Also if I want to update my libraries folder... that should be a git repo I could pull from. I hear symlinks might be able to help but not looking forward to it.
One-to-One Interrupt Source and Interrupt Channel
I've since gotten comfortable with the interrupt architecture but I had thought initially it was odd I couldn't assign multiple interrupt sources to a single interrupt, giving more flexibility. Oh! Reminds me that the docs have legacy info about getbrk which is why I had originally thought interrupts could have more than one source since there is a "what interrupt source is currently active" kind of query. That disappeared after some revision in the design.
Can't use # reg address expressions in CON blocks, example:
About #2: I use flexspin that allows for include directories. I wrote a small wrapper in Python that allows me to declare a project similar to e.g. Rust’s cargo, and this allows then for submodules, I like them to. You can see one example here https://github.com/deets/unifhy-rocket-engine-test-stand/tree/master/modul2/P2 - i used submodules originally, for my fellow collaborators who aren’t that git savvy I had to copy stuff over.
I've been planning on moving to alternative toolchains at some point... may need to do it sooner rather than later. The Python idea is very intriguing. I had to do something similar with a C++ environment to get intellisense working on vscode. Parsed the output of a makefile and modified the vscode's settings.json file to provide search directories, etc. since one library didn't work well with intellisense. Applying something similar here may be a clean workaround, or you know, move to a more different toolchain.
I did a quick test. As expected, regexec/regcall has no place in compiled Spin2 so my serial library won't work. But it was easy enough to mix another Serial library with my formatting library, for example:
As expected, larger binary. Dang, using 2% instead of 1% of memory available... haha.