├── .gitignore
├── LICENSE
├── README.md
├── datasheets
├── Crystal-OSC-ABLS3-25529.pdf
├── P8X32A-Propeller-Datasheet-v1.4.0_0.pdf
└── P8X32A-Web-PropellerManual-v1.2_0.pdf
├── documentation
├── Diving-into-multicore.md
├── IO.md
├── My-first-PASM.md
├── PWM.md
├── Passing-params-in-PASM.md
├── Propeller-IDE-Getting-Started.md
├── README.md
├── Serial-IO.md
├── Your-first-SPIN-program.md
└── images
│ ├── i-can-spin-a-rainbow.png
│ ├── layout-diving-into-multicore.png
│ ├── layout-your-first-spin.png
│ ├── propeller-hat-eeprom.png
│ ├── propeller-hub-cog-diagram.png
│ ├── propeller-ide-download.png
│ └── propeller-ide-serial-terminal.png
├── examples
├── Diving-into-multicore.spin
├── My-first-PASM.spin
├── Passing-params-in-PASM.spin
├── README.md
├── Signalling-with-pins.spin
├── Sweeping-LEDs-PASM.spin
└── Your-first-SPIN-program.spin
├── hardware
├── Propeller-HAT-schematic.pdf
├── Propeller-HAT.brd
├── Propeller-HAT.fzpz
├── Propeller-HAT.sch
├── Propeller-HAT.svg
└── README.md
├── propeller-hat.jpg
├── propeller-ide-download.png
├── software
├── README.md
├── p1load
│ ├── README.md
│ ├── install
│ └── p1load
├── python
│ ├── library
│ │ ├── CHANGELOG.txt
│ │ ├── LICENSE.txt
│ │ ├── MANIFEST.in
│ │ ├── README.md
│ │ ├── README.txt
│ │ ├── p1
│ │ │ ├── __init__.py
│ │ │ ├── io.py
│ │ │ ├── loader.py
│ │ │ ├── pwm.py
│ │ │ └── serialio.py
│ │ ├── setup.py
│ │ └── src
│ │ │ ├── .gitignore
│ │ │ ├── io
│ │ │ ├── I2C slave v1.2.spin
│ │ │ ├── Makefile
│ │ │ └── io.spin
│ │ │ ├── pwm
│ │ │ ├── FullDuplexSerial.spin
│ │ │ ├── Makefile
│ │ │ ├── PWM_32_v4.spin
│ │ │ └── io-pwm.spin
│ │ │ └── serialio
│ │ │ ├── FullDuplexSerial.spin
│ │ │ ├── Makefile
│ │ │ └── serialio.spin
│ ├── packaging
│ │ ├── CHANGELOG
│ │ ├── debian
│ │ │ ├── README
│ │ │ ├── changelog
│ │ │ ├── clean
│ │ │ ├── compat
│ │ │ ├── control
│ │ │ ├── copyright
│ │ │ ├── docs
│ │ │ ├── rules
│ │ │ └── source
│ │ │ │ ├── format
│ │ │ │ └── options
│ │ ├── makeall.sh
│ │ ├── makedeb.sh
│ │ └── makelog.sh
│ └── tools
│ │ ├── binarytoarray.py
│ │ ├── io.arr
│ │ └── lfsr.py
└── sidplay
│ ├── README.md
│ ├── playlist.py
│ ├── sidplay
│ ├── sidplay.py
│ └── src
│ ├── SIDcogSlave
│ ├── CombinedWaveforms.bin
│ ├── FullDuplexSerial.spin
│ ├── Makefile
│ ├── SIDcog.spin
│ └── SIDcogSlave.spin
│ └── sidplay
│ ├── Makefile
│ └── sidplay.c
└── terminal.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | eagleUp/
2 | *.dmp
3 | i__pycache__/
4 | *.py[cod]
5 | dist/
6 | sdist/
7 | env/
8 | build/
9 | develop-eggs/
10 | eggs/
11 | *.egg-info/
12 | .installed.cfg
13 | *.egg
14 | *.o
15 | *.binary
16 | pip-log.txt
17 | pip-delete-this-directory.txt
18 | .DS_Store
19 |
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Pimoroni Ltd.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Propeller HAT, the 8-core microcontroller add-on for your Raspberry Pi.
4 |
5 | Available now from Pimoroni: http://shop.pimoroni.com/products/propeller-hat
6 |
7 | 
8 |
9 | Propeller HAT is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.: http://creativecommons.org/licenses/by-sa/4.0/
10 |
11 | ### Features
12 |
13 | * 8-core Parallax Microcontroller on-board
14 | * 30 IO pins broken out, serial data/programming connection to Pi
15 | * 20 Pi pins broken out for communications/ease of access
16 | * 170pt breadboard for experimentation
17 | * Python quick start library with PWM/Servo and GPIO libraries
18 |
19 |
20 | ### Getting started
21 |
22 | For instant-gratification you can try the Propeller HAT IO libraries:
23 |
24 | * [IO using Serial](documentation/Serial-IO.md)
25 | * [IO using i2c](documentation/IO.md)
26 | * [PWM for LEDs/Servos](documentation/PWM.md)
27 |
28 | You'll need Propeller IDE to start programming your Propeller HAT:
29 |
30 | * [Propeller IDE Getting Started](/documentation/Propeller-IDE-Getting-Started.md)
31 |
32 | ## Propeller IDE Installation
33 |
34 | As always, we've made it super-easy for you to get all the software you need with a nifty one-line installer. To run it fire up Terminal which you'll find in Menu -> Accessories -> Terminal on your Raspberry Pi desktop like so:
35 |
36 | 
37 |
38 | In the new terminal window type:
39 |
40 | ```bash
41 | curl -sS get.pimoroni.com/propellerhat | bash
42 | ```
43 |
44 | This will install a fairly recent version of the Propeller IDE but if you'd like you can head over to [www.lamestation.com/propelleride/](http://www.lamestation.com/propelleride/) and grab the latest
45 | version of Propeller IDE for the Raspberry Pi, which may be newer than the one installed by the one-line installer.
46 |
47 | 
48 |
49 | It's easier if you grab the right URL, and use the wget command on your
50 | Raspberry Pi to download it. For example:
51 |
52 | ```bash
53 | wget https://github.com/parallaxinc/PropellerIDE/releases/download/0.36.7/propelleride-0.36.7-armhf.deb
54 | ```
55 |
56 | Once downloaded, you can install it with:
57 |
58 | ```bash
59 | sudo dpkg -i propelleride-0.36.7-armhf.deb
60 | ```
61 |
62 | ### Documentaton & Support
63 |
64 | * Tutorials - https://learn.pimoroni.com/propeller-hat
65 | * GPIO Pinout - https://pinout.xyz/pinout/propeller_hat
66 | * Get help - http://forums.pimoroni.com/c/support
67 |
68 | ### Repository Contents
69 |
70 | #### Documentation
71 |
72 | Everything you need to get started with Propeller IDE and your first
73 | SPIN program.
74 |
75 |
76 | #### Software
77 |
78 | Suport software and Python-based uploader tool.
79 |
80 | * python - Python library for Propeller HAT with PWM and GPIO functions
81 | * sidplay - Play SID tune dumps with Propeller HAT
82 | * p1load - Installer and binary for Pi-compatible p1load
83 |
84 |
85 | #### Datasheets
86 |
87 | Datasheets for Parallax Propeller and Crystal Oscillator.
88 |
--------------------------------------------------------------------------------
/datasheets/Crystal-OSC-ABLS3-25529.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/datasheets/Crystal-OSC-ABLS3-25529.pdf
--------------------------------------------------------------------------------
/datasheets/P8X32A-Propeller-Datasheet-v1.4.0_0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/datasheets/P8X32A-Propeller-Datasheet-v1.4.0_0.pdf
--------------------------------------------------------------------------------
/datasheets/P8X32A-Web-PropellerManual-v1.2_0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/datasheets/P8X32A-Web-PropellerManual-v1.2_0.pdf
--------------------------------------------------------------------------------
/documentation/Diving-into-multicore.md:
--------------------------------------------------------------------------------
1 |
13 | #Diving Into Multicore
14 |
15 | You probably didn't pick up Propeller HAT because it was some ordinary, run-of-the-mill Microcontroller board. No siree.
16 | You want to take advantage of those 8 cores and play to the Propeller's strengths.
17 |
18 | Well, fortunately, it's really not all that hard.
19 |
20 | ###What's a cog, got to do, got to do with it?
21 |
22 | In the world of Propeller, where almost everything is a pun based on the name of the chip, you'll often find the cores
23 | referred to as "cogs". The Propeller has 8 cogs, and ( wait for it... ) a "hub".
24 |
25 | 
26 |
27 | ####The Hub
28 |
29 | The Hub is the central controller of the Propeller, it houses the lion's share of the chips memory/storage - 8192, 32-bit
30 | longs ( also known as 32kb or 32,768 bytes ). The Hub's job is to dish out tasks to the Cogs, control their access to its
31 | memory and make sure they don't fight over resources or tread on each other's toes.
32 |
33 | In other words, the Hub is the boss! What it doesn't have, however, is the ability to run code. The Hub sits in its tiny
34 | silicon throne and dishes out commands, but it can't execute any itself. The Hub relies wholly and totally on the Cogs to carry
35 | out their instructions and only gets involved when they need to communicate, share data or receive new sets of instructions.
36 |
37 | The Hub also has some other fancy features, such as configuration registers and lock bits- we won't worry about those yet!
38 |
39 | ####The Cogs
40 |
41 | Now. Onto the Cogs. Each Cog has 512, 32-bit longs ( also known as 2kb or 2048 bytes ) of memory. This memory serves as both
42 | storage for the instuctions that Cog has been told to execute, and as running memory for remembering what it's doing.
43 |
44 | 2kb is a pretty decent amount of memory for a Cog, but you have to be mindful that the larger your running code is, the less
45 | space will be available for it to store what it's working on. Think of it like filling a frying pan- the more food you pop
46 | into the frying pan the less space you have to stir it!
47 |
48 | Alongside the memory, each Cog has its own CPU capable of executing the instructions its given, it also has its own
49 | counters and video generator- but we'll worry about those later too.
50 |
51 | The most important thing to remember is that each one of the 8 Cogs has its own DIRA and OUTA register for setting the
52 | direction and output state of all 32 IO pins on the Propeller. When you're passing a function or code to a Cog you need
53 | to make sure that the Cog sets up its own DIRA register, since setting the direction of a pin elsewhere will likely happen
54 | in another Cog and lead to confusing results!
55 |
56 | ###Now, for some code!
57 |
58 | ```spin
59 | CON
60 | _CLKMODE = xtal1 + pll16x
61 | _XINFREQ = 6_000_000
62 |
63 | MY_LED_PIN = 0 ' Use pin A0
64 | SECOND_PIN = 1 ' Use pin A1
65 |
66 | VAR
67 | long stack[128] ' Allocate 128 longs of stack space for our new COG
68 |
69 | PUB main
70 | cognew(blink_second_pin, @stack) ' Start a new COG
71 |
72 | DIRA[MY_LED_PIN] := 1 ' Set the LED pin to an output
73 |
74 | repeat ' Repeat forever
75 | OUTA[MY_LED_PIN] := 1 ' Turn the LED on
76 | waitcnt(cnt + clkfreq) ' Wait 1 second
77 | ' cnt is the clock tick counter,
78 | ' clkfreq is the number of clock ticks in a second
79 | OUTA[MY_LED_PIN] := 0 ' Turn the LED MY_LED_PIN
80 | waitcnt(cnt + clkfreq) ' Wait 1 second
81 |
82 | PUB blink_second_pin
83 | DIRA[SECOND_PIN] := 1
84 |
85 | repeat
86 | OUTA[SECOND_PIN] := 1 ' Turn second LED on
87 | waitcnt(cnt + clkfreq/2) ' Wait half a second
88 | OUTA[SECOND_PIN] := 0 ' Turn second LED off
89 | waitcnt(cnt + clkfreq/2) ' Wait half a second
90 | ```
91 |
92 | You'll notice that the simple act of launching a new Cog has introduced a lot of extra code to our program. Let's
93 | break it down again...
94 |
95 | ####blink_second_pin
96 |
97 | The majority of this is the work we actually want the Cog to do, which is all contained within the PUBlic method
98 | `blink_second_pin`. It's very similar to our main public method because it's blinking another pin.
99 |
100 | To make it clear that the second Cog is running, we pick a different pin, and a faster blink rate.
101 |
102 | As before, we use a CONstant to define which pin we'd like to blink, in this case in A1.
103 |
104 | ####clkfreq/2
105 |
106 | Since `clkfreq` is the number of clock ticks in a single second, we can incur a wait of half a second simply by
107 | dividing it by two.
108 |
109 | ####DIRA and OUTA strike again
110 |
111 | Every single Cog has its own DIRA and OUTA registers, so it's absolutely imperative to remember to set the direction
112 | of the pin you want to use before trying to change its value. If you forget to set a pin to an output
113 | (`DIRA[PIN] := 1`) then it wont output its value when you change it (`OUTA[PIN] := X`).
114 |
115 | ####cognew
116 |
117 | This example introduces another feature of SPIN, the `cognew`1 command. Cognew does what it says on the tin, and
118 | initiates a new Cog to run the SPIN method that you pass it. Cognew has a cousin known as `coginit` which also runs
119 | a spin method in a Cog, but instead of finding the first available unused Cog it gives a new task to the one you specify.
120 |
121 | At this point, it's important to note that the code calling `cognew` is running in a *Cog* and not the *Hub*. So this means you have 7 remaining Cogs to run 7 additional tasks.
122 |
123 | The `cognew` command has a second required parameter, the stack pointer...
124 |
125 | ####stack
126 |
127 | A new `VAR` section has made its way into this example too. In this instance our only variable is the
128 | stack2 we want to reserve for our new Cog. This is a portion of Hub memory which the Cog can use to
129 | store temporary data that it needs to carry it its task.
130 |
131 | When we call `cognew` we pass it the stack variable, the `@` prefix gives us the address of our `stack` array,
132 | rather than its value. Giving it the address means that the newly iniated Cog will know that it's safe to store
133 | values at this location. The stack should always be sized appropriately for whatever task the Cog is allocated.
134 | At this stage we don't really care about optimisation, so we'll use a "safe" and spacious stack that's 128 32-bit
135 | longs in size.
136 |
137 | If you've ever come across the term "stack overflow", it's what happens when an application tries to use more stack
138 | space than there has been allocated for it- this means it'll try and store things in memory locations after the
139 | stack which have potentially been reserved for something else.
140 |
141 | #Wiring up your Propeller HAT
142 |
143 | To see the result of this code, you'll need a couple of LEDs plugged into outputs A0 and A1, like so:
144 |
145 | 
146 |
147 |
148 | #Further Reading
149 |
150 | * 1 A little more detail about Cogs: http://www.parallax.com/propeller/qna/Default.htm#QnaTopics/QnaCogs.htm
151 | * 2 Learn more about the need for Stack on Propeller Cogs: http://www.parallax.com/propeller/qna/Default.htm#CodeTeqTopics/StackSpace.htm
152 |
--------------------------------------------------------------------------------
/documentation/IO.md:
--------------------------------------------------------------------------------
1 | #Propeller HAT IO
2 |
3 | Propeller HAT IO is a Python library which flashes your Propeller HAT with a 28-pin,
4 | general purpose i2c GPIO driver.
5 |
6 | It lets you control 28 pins from A0 to A27, setting them as Inputs or Outputs and
7 | changing them from High to Low with simple i2c commands.
8 |
9 | ##Prerequisites
10 |
11 | Propeller HAT IO requires two female-to-female jump wires making these connections:
12 |
13 | * SDA on the left, to A29 along the bottom
14 | * SCL on the left, to A28 along the bottom
15 |
16 | This connects your Propeller HAT to the Raspberry Pi i2c bus. The Pi has built-in
17 | pull-up resistors, so you don't need to add these yourself.
18 |
19 | ##Usage
20 |
21 | Propeller HAT IO appears on your Raspberry Pi i2c bus 1 as address 0x17 by default.
22 |
23 | To change pin direction and value, you must write registers 0-63, and to read pin
24 | values you must read registers 64-96.
25 |
26 | Pins 28, 29, 30 and 32 are not read or written because these are used for Serial
27 | and i2c communication.
28 |
29 | Basic example to turn on pin 0 in bash:
30 |
31 | ```bash
32 | sudo i2cset -y 1 0x17 0 1 # Write direction register
33 | sudo i2cset -y 1 0x17 32 1 # Write value register
34 | ```
35 | Or to read a pin in bash:
36 |
37 | ```bash
38 | sudo i2cget -y 1 0x17 64 # Read pin 1
39 | ```
40 |
41 | ##Library Reference
42 |
43 | ```python
44 | p1.io.setup(i2c_address)
45 | ```
46 |
47 | Set up the i2c address of the Propeller HAT IO firmware. Only use this if you've
48 | changed the firmware with an i2c address to suit your purposes.
49 |
50 | ```python
51 | p1.io.mode(pin, mode)
52 | ```
53 |
54 | Change the mode of pin to either mode 1, OUTPUT or mode 0, INPUT. You can use
55 | p1.io.OUTPUT and p1.io.INPUT constants for this.
56 |
57 | ```python
58 | p1.io.write(pin,value)
59 | ```
60 | Write a value to . 1 = HIGH, 0 = LOW.
61 |
62 | ```python
63 | p1.io.read(pin)
64 | ```
65 | Read a value from . Returns 1 if the pin is read as HIGH or 0 if it is low.
66 |
67 | **Note:** The Propeller does not have configurable internal pull-up/down resistors
68 | on any of its IO pins. If you want to use an IO pin as an input, an appropriate
69 | pull resistor is recommended to prevent it from floating.
70 |
71 |
--------------------------------------------------------------------------------
/documentation/My-first-PASM.md:
--------------------------------------------------------------------------------
1 |
13 | #My First PASM
14 |
15 | If you're anything like me, you'll see PASM ( Propeller Assembly ) as a looming challenge, begging to be tackled
16 | and surmounted whether or not it proves to be at all useful in your Pi projects.
17 |
18 | Programmers can certainly succumb to "challenge accepted" moments, and PASM is one of those.
19 |
20 | ##Blink
21 |
22 | Like all languages, the canonical way to get started is with a simple and easy blink example. Let's have a look
23 | at one in PASM. What we'll actually see is a small SPIN program loading up a new Cog with the PASM we want to run.
24 | All the code you run on a Propeller will start with a Cog running SPIN.
25 |
26 | ```spin
27 | CON
28 | _CLKMODE = xtal1 + pll16x
29 | _XINFREQ = 6_000_000
30 |
31 | MY_LED_PIN = 0
32 |
33 | PUB main
34 | cognew(@blink, 0) ' Start a Cog with our assembly routine, no stack
35 | ' is required since PASM requires we explicitly
36 | ' assign and use memory locations within the Cog/Hub
37 | DAT
38 | org 0
39 | blink mov dira, Pin ' Set our Pin to an output
40 | rdlong Delay, #0 ' Prime the Delay variable with memory location 0
41 | ' this is where the Propeller stores the CLKFREQ variable
42 | ' which is the number of clock ticks per second
43 | mov Time, cnt ' Prime our timer with the current value of the system counter
44 | add Time, #9 ' Add a minimum delay ( more on this below )
45 | :loop waitcnt Time, Delay ' Start waiting
46 | xor outa, Pin ' Toggle our output pin with "xor"
47 | jmp #:loop ' Jump back to the beginning of our loop
48 |
49 | Pin long |< MY_LED_PIN ' Encde MY_LED_PIN to a bit mask
50 | Delay res 1
51 | Time res 1
52 | fit
53 | ```
54 |
55 | Whew! That's a lot to take in. While at first glance the PASM code may look like incomprehensible nonsense,
56 | it's actually a lot easier to understand than it looks. Assembly doesn't have many of the constructs we take
57 | for granted in most high level programming languages, and that means it doesn't have those complexities either.
58 |
59 | Most of these Assembly commands are simply moving a number from one place to another, or performing an operation
60 | upon two memory locations. Once you get a simple Blink program running, it becomes easier to experiment with how
61 | other instructions affect, for example, your Pin value.
62 |
63 | Onward to the explanation...
64 |
65 | ####cognew
66 |
67 | You'll notice, if you've read through the Multicore tutorial, that our cognew command is ever so slightly different
68 | this time around.
69 |
70 | This is because PASM is wholly different to SPIN in how it operates, and is much more explicit about how memory is
71 | used. SPIN needs a stack to store various snippets of information as it goes about its business, and what it stores
72 | is completely hidden from the programmer, it's a high-level language.
73 |
74 | PASM, on the other hand, only stores things where you tell it, when you tell it and how you tell it.
75 |
76 | The second parameter in this instance becomes the read-only parameter passed into the new Cog. You can specify a
77 | single number, a complicated 32-bits long bitfield, or just give it the memory address for a handful of parameters
78 | stored in the Hub. This is all far too advanced for our first blink, though, so we'll stick with 0.
79 |
80 | ####The Assembly
81 |
82 | The PASM code in this example is quite the monster, even for a simple Blink. We'll tackle it line by line and I'll
83 | try to explain everything to the nth degree. Grab a drink and a snack, and sit tight!
84 |
85 | ```spin
86 | DAT
87 | ```
88 |
89 | All PASM is stored within the DAT section of its parent SPIN program. This is the easiest place to store PASM source
90 | which everyone can see and modify, but it's not the only way. You could use an array of longs to store
91 | compiled PASM instructions, or you could create PASM instructions on the fly ( please don't! for your own sanity! ).
92 |
93 | ```spin
94 | org 0
95 | ```
96 |
97 | This is some PASM copypasta that you'll find at the top of most, if not all, blocks of PASM code in some form or
98 | another. It simply states that the following PASM code should start at Cog RAM addr 0.
99 |
100 | ```spin
101 | blink mov dira, Pin
102 | ```
103 |
104 | There's a lot going on in this line, but it's easy enough to break down.
105 |
106 | The `blink` part is a label, this is a little note to the compiler telling it that we want to keep track of this
107 | point in the program so we can find it later. This label can be passed into `cognew` to tell it where to locate our PASM. It can also be jumped to in PASM itself, you'll see this later.
108 |
109 | Next comes the actual instruction: `mov dira, Pin`. The `mov` part is a simple mnemonic, a text name for a numerical
110 | instruction that the Propeller can understand. If you hadn't guessed, it means "move" although it actually copies.
111 |
112 | The rest of the instruction is made up of our destination, `dira` which is the address ( not the value ) of the
113 | DIRA register, the very same one we use in SPIN. And, finally, the address of our source `Pin` which is a 32bit integer containing the pin mask we want to toggle.
114 |
115 | So this instruction is telling the Propeller to `mov` the value of memory location `Pin` into register `dira`. Well,
116 | copy, since the Pin value remains unchanged.
117 |
118 | Bear in mind that we're blatting the whole register by moving Pin into it, so our Pin will be the *only* output.
119 |
120 | A far more appropriate instruction would be `or dira, Pin`, which would turn the Pin to an output if its not one,
121 | and would otherwise leave it unchanged.
122 |
123 | ```spin
124 | rdlong Delay, #0
125 | ```
126 |
127 | Next up is a Hub access instruction. Propeller Assembly includes special instructions for accessing Hub memory.
128 | This particular one, `rdlong`, reads a long ( a 32bit integer ) into its target from a source memory location.
129 |
130 | In this instance `Delay` is our target, a long we've reserved for our use, and the source is `#0` which is a
131 | *literal* memory address. So, we're loading Delay from Hub memory location 0. This just so happens to be where the
132 | Propeller keeps the CLKFREQ value, which is the number of clock ticks in a second. Using this, we can create a 1sec
133 | delay later.
134 |
135 | ```spin
136 | mov Time, cnt
137 | ```
138 |
139 | Just like our earlier `mov` instruction, we're copying the value of one memory address or register into another.
140 |
141 | In this case we're priming `Time` with the value of the system counter, for which there's a handy shortcut `cnt`
142 | so you don't have to remember its numeric memory location.
143 |
144 | ```spin
145 | add Time, #9
146 | ```
147 |
148 | Now for an `add` instruction. This one should be easy to understand. We're adding the literal value 9 ( we indicate
149 | that it's not an address by prefixing with # ) to our Time variable.
150 |
151 | But, why on earth are we doing this? The reason is perplexing, but simple once you understand it.
152 |
153 | The `waitcnt` instruction in PASM will wait until the `cnt` register equals the value we give it. We're passing
154 | it the value of `Time` for its first wait, if this value simply equalled the system counter then the very act of
155 | calling `waitcnt`, which itself takes time, will cause us to miss the value we're looking for.
156 |
157 | > Imagine I gave you a piece of paper with the number 30 on it, and told you at exactly 30 seconds past
158 | to wait until the clock next shows 30 seconds. By the time I've finished telling you what to do it's going to be
159 | at least 32 seconds past- so you'll wait nearly a whole minute instead of the 30 seconds I wanted.
160 |
161 | > When waitcnt misses a particular value of cnt, this is more or less what's happening!
162 |
163 | A more succinct way to write this line would be:
164 |
165 | ```spin
166 | add Time, Delay
167 | ```
168 |
169 | Which causes our first `waitcnt` delay to be about 1 second, instead of the minimum possible delay. However I
170 | deliberately left this minimum wait to illustrate a common tripping point in PASM.
171 |
172 | ```spin
173 | :loop waitcnt Time, Delay
174 | ```
175 |
176 | Now we start waiting. This line does two things.
177 |
178 | * First `waitcnt` will wait until the system counter matches the value we've specified in `Time`.
179 | * Second, the value of `Delay` will be added to `Time` to create the next value to wait for.
180 |
181 | Because `Delay` is added to `Time` for us, there's no need to do it manually within the loop, and the next
182 | time we call `waitcnt` in the same way, we'll handily get another 1 second delay.
183 |
184 | This is, of course, unless all the things we've decided to do within the loop take more than the delay time!
185 |
186 | The `:loop` prefix on this line is another label. Using ':' to prefix a label is a handy way of making it
187 | obvious that it's a label, and not a variable, register address or instruction mnemonic. We've labelled this
188 | line because, in order to loop, we want to jump back to it later.
189 |
190 | The word "loop" is not required, you can make this label ":monkeys" if you want!
191 |
192 | ```spin
193 | xor outa, Pin
194 | ```
195 |
196 | This line is where the magic happens. We're finally setting a value to our output register `outa`.
197 | Using `xor` is a *really* lazy way of toggling our output pin, since it literally means "exclusive or".
198 |
199 | So, if our pin is on, we get:
200 |
201 | `1 xor 1 = 0`
202 |
203 | And if our pin is off, we get:
204 |
205 | `0 xor 1 = 1`
206 |
207 | And so on!
208 |
209 | The thing to remember here is that xor is operating upon the whole 32bit register, so `xor` is a really handy
210 | way to toggle a pin using a bit mask, without affecting the others.
211 |
212 | ```spin
213 | jmp #:loop
214 | ```
215 |
216 | And now we're finally jumping back to the label we set earlier, completing the loop and resulting in the `xor`
217 | on our output register being run about once a second.
218 |
219 | You can `jmp` to any memory address you like, but using a label makes it much easier to keep track of where the
220 | jump is going.
221 |
222 | ```spin
223 | Pin long |< MY_LED_PIN
224 | ```
225 |
226 | This line creates a new, long type variable called Pin which we're assiging with a bitmask decoded from our
227 | MY_LED_PIN constant. The decode operator "|<" will turn 1 into 0001, 2 into 0010, 3 into 0100 and so on.
228 |
229 | This is the bitmask we use when calling `xor` against the output register. Remember:
230 |
231 | * `0001 xor 0001 = 0000` ie: turns pin On
232 | * `0000 xor 0001 = 0001` ie: turns pin Off
233 |
234 |
235 | ```spin
236 | Delay res 1
237 | Time res 1
238 | ```
239 |
240 | These two lines reserve longs of memory using the `res` directive. We can reserve 1 or more longs, but since Time
241 | and Delay both fit into a single 32-bit integer we'll only use 1.
242 |
243 | `res` is a directive, not an instruction, this means it's evaluated by the compiler and never run as PASM. Upon
244 | evaluation it just leaves gaps in the Cog memory and gives them the friendly names, symbols, which we can refer
245 | to them by in our code.
246 |
247 | The symbols ( or labels ) Delay and Time don't exist as far as PASM is confirmed, they're just friendly names
248 | for us to re-use that represent memory addresses.
249 |
250 | In plain English, these commands mean "leave the next memory address empty and call it Delay so we can use it elsewhere".
251 |
252 | ```spin
253 | fit
254 | ```
255 |
256 | This final directive isn't essential, specially when we're dealing with such small amounts of PASM code, but it's
257 | useful to remember. `fit` is another instruction to the compiler, it simply asks "does all the PASM we've written
258 | actually fit into Cog RAM?"
259 |
260 | `fit` will generate a compiler error if we've written too much code to fit into a single Cog. At this point we'd
261 | need to either cut down the code by optimising it, or split its jobs over muliple Cogs.
262 |
263 | ##Whew!
264 |
265 | Well, that was an explanation marathon. Go and cool off your brain for a minute, and then get ready to compile
266 | and run your code. For this example you can use the same layout we used in the SPIN blink example:
267 |
268 | 
269 |
--------------------------------------------------------------------------------
/documentation/PWM.md:
--------------------------------------------------------------------------------
1 | #Propeller HAT PWM
2 |
3 | Propeller HAT PWM is a Python library which flashes your Propeller HAT with a 30-pin
4 | PWM driver library for controlling LEDs or servos.
5 |
6 | It lets you drive 30 pins from A0 to A29, outputting PWM pulses, duty cycles or servo
7 | commands with a simple serial protocol.
8 |
9 | ##Prerequisites
10 |
11 | Propeller HAT PWM communicates over serial, so you don't need any extra wiring.
12 |
13 | ##Library Reference
14 |
15 | ```python
16 | p1.pwm.duty(pin, duty, freq)
17 | ```
18 |
19 | PWM the pin with a duty cycle of duty ( 0 to 100% ) at the defined frequency.
20 |
21 | The value for requency is calculated like so: 1/Desired Frequency * 1000 * 1000
22 |
23 | So if you want 50Hz, it's 1/50 * 1000 * 1000, or 20,000, eg: `p1.pwm.duty(0, 50, 20000)`.
24 |
25 | ```python
26 | p1.pwm.pulse(pin,on_time,off_time)
27 | ```
28 |
29 | Pulse a pin with on_time on duration and off_time off duration. Pulse accepts values between 0 and 65535.
30 |
31 | The On and Off times are measured in units of 8.2us, giving a range of 0 to 537,387 ( or about 0.53 sec )1.
32 |
33 | For example `p1.pwm.pulse(0,60975,60975)` is the closest you can get to toggling a pin every 0.5sec.
34 |
35 | ```python
36 | p1.pwm.servo(pin, pulse)
37 | ```
38 |
39 | Drive a servo with a specific pulse width in nanoseconds.
40 | Look up your servo datasheet to see what pulse width corresponds to your desired angle.
41 |
42 |
43 | ####Notes
44 |
45 | * 1 I may expand this to a 3-byte integer ranging from 0 to 16,777,215, or 0 to 137sec, but since
46 | the Pi is fine at long pulse intervals it wouldn't be much use!
47 |
48 |
--------------------------------------------------------------------------------
/documentation/Passing-params-in-PASM.md:
--------------------------------------------------------------------------------
1 |
13 | #Passing params in PASM
14 |
15 | This example shows you how to pass a start address for a set of paramaters to your new Cog as the boot parameter. You can
16 | then read each paramater, as a long or a byte, by incrementing the supplied Address and using the rdlong and rdbyte instructions
17 | to retrieve them from the Hub.
18 |
19 | This is a pretty standard way to bootstrap your Cog with all the information it needs to do its job, and is also a handy way
20 | to provide arrays or single memory locations where the Cog can deposit the result of its work.
21 |
22 | For example, you could define a LENGTH var, followed by a LED_PATTERN var and produce code in PASM which reads each byte from
23 | LED_PATTERN in turn and flashes the LEDs. Perhaps we'll cover such a thing later.
24 |
25 | For now, a simple example:
26 |
27 | ```spin
28 | CON
29 | _CLKMODE = xtal1 + pll16x
30 | _XINFREQ = 6_000_000
31 |
32 | VAR
33 | long MY_PIN_1, MY_PIN_2 ' These will appear next to each other in memory
34 |
35 | PUB main
36 | MY_PIN_1 := |< 0 ' Set our first pin to a bitmask for A0
37 | MY_PIN_2 := |< 1 ' And our second for A1
38 | cognew(@blink, @MY_PIN_1) ' Supply the address of the first parameter
39 |
40 | DAT
41 | org 0
42 | blink mov addr, par ' Load our address from the boot param
43 | rdlong Pn, addr ' Read the first pin number
44 | add addr, #4 ' Increment addr by 1 long ( 4 bytes )
45 | rdlong Pn2, addr ' Read the second pin number
46 |
47 | or dira, Pn ' Set up pins as outputs
48 | or dira, Pn2 ' It's good to do stuff while we're waiting
49 | ' for the Hub to come back around, since we
50 | ' only just synced for a rdbyte!
51 |
52 | rdlong Delay, #0 ' Prepare the delay
53 | mov Time, cnt ' Prep the wait time
54 | add Time, #9 ' Add the minimum wait time
55 |
56 | :loop waitcnt Time, Delay ' Start blinking!
57 | xor outa, Pn
58 | xor outa, Pn2
59 | jmp #:loop
60 |
61 | Pn res 1 ' Store our first LED pin
62 | Pn2 res 1 ' Store our second LED pin
63 | Addr res 1 ' Store our parameter address
64 | Delay res 1 ' Store the delay increment
65 | Time res 1 ' Store the current time for wait
66 | fit
67 | ```
68 |
69 | ####Breaking it down
70 |
71 | I'm going to assume you've read [My First Pasm](/documentation/My-first-PASM.md) and skim over much of the basics.
72 |
73 | `long MY_PIN_1, MY_PIN_2`
74 |
75 | In our PASM code, we're declaring two variables next to each other. These will appear adjacent to each other in HUB memory as two sets of 4 bytes, or 2 longs. These are the longs we want to copy to our COG!
76 |
77 | ```
78 | MY_PIN_1 := |< 0
79 | MY_PIN_2 := |< 1
80 | ```
81 |
82 | In our `main` method, we're setting the values of `MY_PIN_1` and `MY_PIN_2` to be bit masks, by using our old friend the bitwise decode operator `|<`. Practically speaking, this will convert `0` to `%0` and `1` to `%10` etc.
83 |
84 | We use bit masks because these can be `or`'d against our output registers to flip those bits to 1. Or `xor`d to toggle them.
85 |
86 | It's worth noting that in SPIN and PASM you use `%` to denote a binary number, like `%10101010` and `$` to denote a hexadecimal number like `$AA`.
87 |
88 | `mov addr, par`
89 |
90 | The very first line of our PASM ( remember that "blink" in this case is a label, and not part of the instruction ) deals with
91 | the `par` register. This register always starts off containing the parameter that's passed into it via `cognew`.
92 | In this case we've passed it the Hub address of `MY_PIN_1`, and it can use this address to locate that value in the Hub when it
93 | wants to read it.
94 |
95 | `rdlong Pn, addr`
96 |
97 | The second line executes what's known as a HUB instruction. The instruction `rdlong` waits for the HUB to come around, then reads a long ( 4 bytes ) into the target location. In this instance Pn is our memory location within the COG and is where we want to copy the value of `MY_PIN_1`.
98 |
99 | `add addr, #4`
100 |
101 | Now that we've read one long from HUB memory, we want to advance to the next one. Addresses are byte-aligned, which means we can read one byte at a time. Since we want the next 4 bytes, and not just the last 3 of the previous long plus the first of the next long, we'll increment our `addr` register by 4. 4 bytes = 1 long.
102 |
103 | `rdlong Pn2, addr`
104 |
105 | Now we've got a pointer to `MY_PIN_2`, which is a long in memory right next to `MY_PIN_1` we can use the `rdlong` instruction to read it into `Pn2`.
106 |
107 | Hooray. We've successfully copied two setting values from HUB memory into our COG!
108 |
109 | `or dira, Pn`
110 |
111 | In this next line we're simply `or`ing the value of `Pn` against `dira`- this sets it as an output. The bit that's set in the `Pn` mask will flip to 1 in the output register. For example `0000 or 0100 = 0100`.
112 |
113 | Everything else you should remember from [My First Pasm](/documentation/My-first-PASM.md), we set up a loop using `waitcnt` and `jmp` and use `xor` ( `1 xor 1 = 0, 0 xor 1 = 1` ) to blink the LEDs.
114 |
--------------------------------------------------------------------------------
/documentation/Propeller-IDE-Getting-Started.md:
--------------------------------------------------------------------------------
1 |
13 | #Propeller IDE Getting Started
14 |
15 | ##Raspberry Pi 3
16 |
17 | The Raspberry Pi 3 does strange things with Serial for the benefit of Bluetooth. Unfortunately this completely trounces `propman` and any other Propeller HAT loader. You can fix it by making sure your Pi 3 is up-to-date ( `sudo apt-get update && sudo apt-get upgrade` ) then edit `/boot/config.txt` and adding the line:
18 |
19 | ```
20 | dtoverlay=pi3-miniuart-bt
21 | ```
22 |
23 | ##Raspbian Jessie
24 |
25 | With the [release of Raspbian Jessie](https://www.raspberrypi.org/downloads/raspbian/), Qt5.3 is available without having to mess about with adding new sources and installing things from backports. If you're using Raspbian Jessie then just:
26 |
27 | * Download the latest Propeller IDE from: http://developer.parallax.com/propelleride/
28 | * Install with: `sudo dpkg -i propelleride-*`
29 | * Install dependencies with `sudo apt-get install -f`
30 |
31 | That's it!
32 |
33 | ##Update
34 |
35 | Propeller IDE 0.36.7 is the latest recommended build. These instructions have been updated to reflect the 0.36.7 install process. Enjoy!
36 |
37 | You can find out more about the new Propeller IDE here: https://github.com/parallaxinc/PropellerIDE/releases/tag/0.36.7
38 |
39 | ##Preface
40 |
41 | Learning to program isn't just about mastering a particular programming language
42 | and applying it in every situation. It's about learning the key concepts
43 | and applying them to a wealth of different situations in many languages.
44 |
45 | The phrase "If you've only got a hammer, everything looks like a nail," springs to mind.
46 | Different circumstances often beg for, or even require, different programming languages.
47 |
48 | **SPIN**
49 |
50 | The native language of the Parallax Propeller is SPIN. Spin is a little Pythonic in nature,
51 | it uses spaces and indentation a syntax.
52 |
53 | It also borrows a lot of syntax quirks from other languages, and thus isn't going to be
54 | familiar from the get go. That's no problem, you'll master it in no time!
55 |
56 | **Propeller IDE**
57 |
58 | The weapon-of-choice software for writing Propeller SPIN is the Open-Source Propeller IDE.
59 | It runs on the Raspberry Pi pretty well, and we've made sure you can upload code right onto
60 | your Propeller HAT painlessly so you can get programming quickly and avoid the hassle of setting up.
61 |
62 | The great thing about Propeller IDE, SPIN and the Propeller is that they're close-knit and
63 | unencumbered by the need to support lots of different processors. This makes compiling and uploading
64 | SPIN code absolutely lightning fast- Arduino users will be simply blown away.
65 |
66 | ##First Steps
67 |
68 | ###Installing Pre-requisites ( Raspbian Wheezy only )
69 |
70 | If you're running Raspbian Jessie, please skip to Installing Propeller IDE below.
71 |
72 | Raspbian Wheezy needs a little helping hand with some of Propeller IDE's dependencies, but hopefully a future
73 | release will see the end of these steps.
74 |
75 | First, you'll need to install the `apt-transport-https` package for apt:
76 |
77 | ```
78 | sudo apt-get install apt-transport-https
79 | ```
80 |
81 | Next, add the following entries to `/etc/apt/sources.list` ( Note the "https://" and the lack of "main" ):
82 |
83 | ```
84 | deb https://twolife.be/raspbian/ wheezy backports
85 | deb-src https://twolife.be/raspbian/ wheezy backports
86 | ```
87 |
88 | Add the repository key.
89 |
90 | ```bash
91 | sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-key 2578B775
92 | ```
93 |
94 | And finally update and install Qt5 and its dependencies, plus libftdi1 for the loader.
95 |
96 | ```bash
97 | sudo apt-get update
98 | sudo apt-get install qt5-default qt5-qmake libqt5serialport5 libegl1-mesa libgles2-mesa libftdi1
99 | ```
100 |
101 | Once that is done, you may want to comment out or remove the entries added to sources.list as they are no longer necessary. To do this, simply place a `#` before them, like so:
102 |
103 | ```
104 | #deb https://twolife.be/raspbian/ wheezy backports
105 | #deb-src https://twolife.be/raspbian/ wheezy backports
106 | ```
107 |
108 | ###Installing Propeller IDE
109 |
110 | Now, head over to [developer.parallax.com/propelleride/](http://developer.parallax.com/propelleride/) and grab the latest
111 | version of Propeller IDE for the Raspberry Pi.
112 |
113 | 
114 |
115 | It's easier if you grab the right URL, and use the wget command on your
116 | Raspberry Pi to download it. For example:
117 |
118 | ```bash
119 | wget https://github.com/parallaxinc/PropellerIDE/releases/download/0.36.7/propelleride-0.36.7-armhf.deb
120 | ```
121 |
122 | Once downloaded, you can install it with:
123 |
124 | ```bash
125 | sudo dpkg -i propelleride-0.36.7-armhf.deb
126 | ```
127 |
128 | ###Turning off the Serial Terminal so you can talk to Propeller HAT
129 |
130 | By default, the Raspberry Pi fires up a serial terminal on /dev/ttyAMA0. This is handy for debugging headless, but if you're using Propeller IDE and programming a Propeller HAT then you've likely got a monitor plugged in anyway!
131 |
132 | The serial terminal must be disabled so that we can communicate with Propeller HAT. Fortunately, raspi-config makes this easy:
133 |
134 | ```bash
135 | sudo raspi-config
136 | ```
137 |
138 | Then navigate to Advanced Options, find the Serial option and disable it.
139 |
140 | 
141 |
142 | ###Making sure propman can access your Raspberry Pi's GPIO pins
143 |
144 | On Wheezy we need propman to run as root, so it can access the GPIO pin used for resetting Propeller HAT:
145 |
146 | ```bash
147 | sudo chown root:root /usr/bin/propman
148 | sudo chmod 4755 /usr/bin/propman
149 | ```
150 |
151 | propman defaults to using GPIO pin 17, pulled low when built for the Raspberry Pi, so this is all we need to do. You're good to go! Uploading code is as simple as:
152 |
153 | ```bash
154 | propman my-binary-file.binary
155 | ```
156 |
157 | And to compile a SPIN file to a binary outside of the IDE, you can:
158 |
159 | ```bash
160 | openspin my-spin-file.spin
161 | ```
162 |
163 | #What next?
164 |
165 | * [Your first SPIN program](/documentation/Your-first-SPIN-program.md)
166 |
--------------------------------------------------------------------------------
/documentation/README.md:
--------------------------------------------------------------------------------
1 | #Propeller HAT Documentation
2 |
3 | Ahoy! If you're reading this, you're probably the proud over of a shiny new Propeller HAT.
4 | If so, thanks for picking one up, and I hope you enjoy discovering the quirks of this powerful little Micro Controller as much as I did.
5 |
6 | ##Propeller IO Quick Start
7 |
8 | The Propeller HAT Python library includes a set of IO modules which, when loaded, automatically flash your Propeller HAT with firmware to handle things like PWM and basic Input/Output.
9 |
10 | The best way to explorer these is to install the Propeller HAT library and run one of them:
11 |
12 | ```bash
13 | sudo pip install p1
14 | sudo python -im p1.pwm
15 | ```
16 |
17 | This loads p1.pwm, a PWM library for Propeller HAT which gives you 30 software PWM pins handled by the Propeller itself and uninterrupted by anything you might do on the Pi.
18 |
19 | #What next?
20 |
21 | * [Propeller IDE Getting Started](/documentation/Propeller-IDE-Getting-Started.md) - Learn how to install Propeller IDE
22 |
--------------------------------------------------------------------------------
/documentation/Serial-IO.md:
--------------------------------------------------------------------------------
1 | #Propeller HAT Serial IO
2 |
3 | Propeller HAT Serial IO is a Python library which flashes your Propeller HAT with
4 | a 30-pin, general purpose Serial GPIO driver.
5 |
6 | It lets you control 30 pins from A0 to A29, setting them as Inputs or Outputs and
7 | changing them from High to Low with simple serial commands.
8 |
9 | ##Prerequisites
10 |
11 | Propeller HAT Serial IO doesn't require any special hardware setup.
12 |
13 | ##Usage
14 |
15 | Propeller HAT Serial IO talks to your Raspberry Pi over serial.
16 |
17 | ###Reading Pins
18 |
19 | Every time an INPUT pin value changes, it will report its state.
20 | Each pin belongs in a bank of 5 pins, and all 5 of these pins will
21 | have their state reported together. So, if 5 pins on one bank change
22 | you will see one byte of update data, if 5 pins on 5 different banks
23 | change you will see 5 bytes of update data.
24 |
25 | **You can read the update data as follows:**
26 |
27 | Bit 0 - 2 | 3 | 4 | 5 | 6 | 7
28 | ----------|----|----|----|----|----
29 | Bank #1-6 | p1 | p2 | p3 | p4 | p5
30 |
31 | The first 3 highest bits ( 0b11100000 ) are the bank number, starting at
32 | 1 and ending at 6.
33 |
34 | The last 5 bite ( 0b00011111 ) represent the state of each pin in that bank.
35 | 1 = HIGH and 0 = LOW.
36 |
37 | So:
38 |
39 | * Bank = (BYTE & 0b11100000) >> 5
40 | * Pin states
41 | * 0 = BYTE & 0b00010000
42 | * 1 = BYTE & 0b00001000
43 | * ... and so on
44 |
45 | **Pins are mapped into banks like so:**
46 |
47 | Bank # | Pins
48 | -------|-----------
49 | 1 | A0 to A4
50 | 2 | A5 to A9
51 | 3 | A10 to A14
52 | 4 | A15 to A19
53 | 5 | A20 to A24
54 | 6 | A25 to A29
55 |
56 | ###Writing Pins
57 |
58 | To change pin direction and value, you must send a single byte
59 | containing a 3-bit CMD on the highest 3 bits, and a 5-bit pin
60 | number to tell the Propeller which pin to act upon.
61 |
62 | Bit | 7 | 6 | 5 | 4 to 0
63 | ---------|---|--------------------------|--------------------------|--------
64 | Function | 0 | 0 = Direction, 1 = State | 0 = In,Low, 1 = Out,High | Number of pin to change from 0-29
65 |
66 | * 0b00100001 = Set pin 1 to OUTPUT
67 | * 0b01100001 = Set pin 1 to HIGH
68 |
69 | Pins 30 and 31 are not read or written because these are used for Serial communication.
70 |
71 | ###Request FW version
72 |
73 | Setting bit 7, the highest CMD bit, high switches to CMD mode. At
74 | the moment this will always cause the Propeller HAT to emit the
75 | FW_VERSION constant stored in the binary.
76 |
77 | Bits 6 to 0 in this instance are reserved for future functionality.
78 |
79 | ##Library Reference
80 |
81 | ```python
82 | p1.serialio.mode(pin, mode)
83 | ```
84 |
85 | Change the mode of pin pin to either mode 1, OUTPUT or mode 0, INPUT. You can use
86 | p1.io.OUTPUT and p1.io.INPUT constants for this.
87 |
88 | ```python
89 | p1.serialio.write(pin,value)
90 | ```
91 | Write a value to pin. 1 = HIGH, 0 = LOW.
92 |
93 | ```python
94 | p1.serialio.read(pin)
95 | ```
96 | Read a value from pin. Returns 1 if the pin is read as HIGH or 0 if it is low.
97 |
98 | **Note:** This actually reads values from a list stored in Python, since the Propeller
99 | automatically emits updated pin states and no explicit read command exists.
100 |
101 | Here's a quick example of using p1.serialio in an interactive Python shell. The
102 | -i command for Python runs in interactive mode, and the -m command will load
103 | a specific module, in this case p1.serialio, saving typing out "import p1.serialio".
104 |
105 | ```bash
106 | pi@raspberrypi ~ $ sudo python -im p1.serialio
107 | Setting up Propeller HAT
108 | Connected (version=1)
109 | Sending code (1084 bytes)
110 | >>> mode(2,1)
111 | >>> write(2,1)
112 | >>> mode(3,1)
113 | >>> write(3,1)
114 | >>>
115 | ```
116 |
117 | **Note:** The Propeller does not have configurable internal pull-up/down resistors
118 | on any of its IO pins. If you want to use an IO pin as an input, an appropriate
119 | pull resistor is recommended to prevent it from floating.
120 |
--------------------------------------------------------------------------------
/documentation/Your-first-SPIN-program.md:
--------------------------------------------------------------------------------
1 |
13 | #Your first SPIN Program
14 |
15 | ###What is SPIN?
16 |
17 | SPIN ( get it? Spin a Propeller? ) is the language of the Propeller chip. It's actually unique to the Propeller,
18 | found nowhere else. Surprisingly it's also an interpreted language. This means it's not actually compiled into a set of
19 | instructions that the Propeller chip understands natively, but is instead run in a tiny interpreter inside the chip1.
20 |
21 | Propeller's native language is PASM, or "Propeller Assembly." It's a little beyond the scope of your Propeller HAT journey,
22 | though, so we'll ignore it for now.
23 |
24 | ###What makes up a SPIN program?
25 |
26 | Every SPIN program consists of functions, variables, constants and data indicated by "Block Designators". These concepts
27 | are common to most programming languages, but SPIN is strict about how and where they appear.
28 |
29 | The block types in SPIN are:
30 |
31 | * `CON` - Declares a block of Constants, such as `LED_PIN = 1`
32 | * `VAR` - Declares a block of Variables, such as `led_state := 0`
33 | * `OBJ` - Declares a block of Objects, these load external code ( a bit like Python's import ) for you to use in your program
34 | * `PUB` - Declares a single public method- if you were loading your code as an object, you could call this method
35 | * `PRI` - Declares a single private method- this would be hidden when loading your code as an object
36 | * `DAT` - Declares a block of data, this is often used to store chunks of Propeller Assembly
37 |
38 | In Propeller IDE, each of these blocks will be displayed with its own distinct background colour, and adjacent blocks of
39 | the same kind will have alternating shades to differentiate them. This gives most SPIN examples their colourful and
40 | somewhat controversial looks:
41 |
42 | 
43 |
44 | The `CON` block is also used to declare some important settings such as the Clock Mode, and Crystal Frequency, which
45 | let your program know what sort of environment it's running in.
46 |
47 | A bare-bones SPIN program might look something like this:
48 |
49 | ```spin
50 | CON
51 | _CLKMODE = xtal1 + pll16x
52 | _XINFREQ = 6_000_000
53 |
54 | MY_LED_PIN = 0 ' Use pin A0
55 |
56 | PUB main
57 | DIRA[MY_LED_PIN] := 1 ' Set the LED pin to an output
58 |
59 | repeat ' Repeat forever
60 | OUTA[MY_LED_PIN] := 1 ' Turn the LED on
61 | waitcnt(cnt + clkfreq) ' Wait 1 second
62 | ' cnt is the clock tick counter,
63 | ' clkfreq is the number of clock ticks in a second
64 | OUTA[MY_LED_PIN] := 0 ' Turn the LED off
65 | waitcnt(cnt + clkfreq) ' Wait 1 second
66 | ```
67 |
68 | Let's break this down step-by-step...
69 |
70 | ####_CLKMODE and _XINFREQ
71 |
72 | These might look like complicated arcane magic at first, but they're really nothing to be worried about.
73 | On Propeller HAT these two lines will always be the same.
74 |
75 | `_CLKMODE` is being set with the value `xtal1 + pll16x` to state that we want to use the external crystal oscillator,
76 | and set the system clock to its value, multiplied by 16x using the PLL2.
77 |
78 | `_XINFREQ` is simply set with the frequency of the external clock. On Propeller HAT we use a 6Mhz crystal, so that's 6000000.
79 | We use understores, which are ignored by SPIN when found in numbers, to make the big number read clearly at a glance.
80 |
81 | ####Assigning "MY_LED_PIN"
82 |
83 | Propeller HAT has 30 user pins from 0 to 29, pins 30 and 31 are tied to your Pi's serial port for communication.
84 |
85 | To assign our LED constant we pick one of the available pins ( labelled A0 to A29 on the board ) and use the corresponding
86 | number. Because we're assigning a constant, we use the "Constant Assignment" operator which is simply `=`:
87 |
88 | ```spin
89 | MY_LED_PIN = 0 ' Use pin A0
90 | ```
91 |
92 | ####DIRA and OUTA
93 |
94 | Behind the scenes of Arduino you'll find something very much like these. They are known as Registers. `DIRA` and `OUTA` both refer to physical, 32-bit locations onboard the Propeller chip itself and the values of each bit in these locations correspond directly to the Direction ( `DIRA` ) and Output Value ( `OUTA` ) of each hardware pin.
95 |
96 | Think of a register as 32 physical on-off switches which you can change from your code, since this is fundamentally what it is.
97 |
98 | **Note:** In the Propeller world every single core or cog has its own `DIRA` and `OUTA` register, and the values of these are "OR'd" together to form the final direction and output values of each pin. If *any* cog tells a pin to output a 1, that pin will output a 1, and if any* cog sets a pin to an output that pin will be an output. Keep this in mind, or it'll almost certainly trip you up when you start using more than one core!
99 |
100 | Here are some of the ways you can assign a state to the output and direction registers:
101 |
102 | ```spin
103 | OUTA := %00000000_00000000_00000000_00000001
104 | OUTA[0..3] := %1000
105 | OUTA[0] := 1
106 | OUTA[0]~~ ' Set to 1, high
107 | OUTA[0]~ ' Set to 0, low
108 | ```
109 |
110 | When setting any variable within SPIN you should use `:=` instead of `=` since `=` is the "Constant Assignment" operator
111 | and should only ever be used to assign constants.
112 |
113 | I don't use `OUTA[0]~~` or `OUTA[0]~` because I think they're unecessarily obtuse and confusing. `OUTA[0] := 1` and `OUTA[0] := 0` are longer, but easier to understand at a glance.
114 |
115 | ####repeat
116 |
117 | SPIN uses a `repeat` command, this is similar to a for or while loop and there are many ways to change its behaviour which we'll cover in later examples. Right now we'll just use `repeat` on its own to create an infinite loop.
118 |
119 | Notice that the lines underneath repeat are indented? This is because, like Python, SPIN uses intentation as syntax (to convey meaning ). In this instance, the indented lines are the ones we want to be repeated. If you're a keen pythonista, you should also take note that there's no ":" on the end of "repeat".
120 |
121 | ```spin
122 | repeat
123 | ' Everything you want to be repeated
124 | ' should be indented under the repeat command
125 | ```
126 |
127 | ####waitcnt
128 |
129 | SPIN's `waitcnt` command, meaning simply "Wait for Counter" is similar in purpose to Python's sleep but conceptually a little different. What you're actually doing here is waiting for the clock counter to reach a specific value. Normally you'll want to wait some multiple of seconds, and it just so happens that the value `clkfreq` always contains the number of clock ticks in a second. Multiply it by 10 and you get a 10 second wait, divide it by 10 and you get a tenth of a second wait, easy!
130 |
131 | ```spin
132 | waitcnt(cnt + (clkfreq/10)) ' Wait 0.1 seconds
133 | waitcnt(cnt + (clkfreq*10)) ' Wait 10 seconds
134 | ```
135 |
136 | #Wiring up your Propeller HAT
137 |
138 | To see the result of this code, you'll need an of LED plugged into outputs A0, like so:
139 |
140 | 
141 |
142 | #Uploading the code
143 |
144 | To build and upload the code, you'll need either Propeller IDE on your desktop/laptop computer, or on your Raspberry Pi.
145 |
146 | On the Pi it should be as simple as hitting the "Run" arrow ( the arrow pointing to the right ) and it'll upload
147 | right onto your Propeller HAT. If this doesn't work you should try p1load. When you compile/build your program in
148 | Propeller IDE it will generate a binary alongside the .spin file.
149 |
150 | To flash a compiled binary you can use either p1load, supplied in this GitHub repository,
151 | or the Python p1.loader from pip. You can do this with a binary built on the Pi, or with one you've uploaded
152 | from your desktop/laptop computer.
153 |
154 | If you have p1load installed you can flash this binary with:
155 |
156 | ```bash
157 | p1load binary_file.binary
158 | ```
159 |
160 | The default should ensure it gets uploaded to Propeller HAT and run.
161 |
162 | If you don't, you can use "p1.loader" in Python, like so:
163 |
164 | ```bash
165 | sudo pip install p1
166 | sudo python -m p1.loader upload -g 17 binary_file.binary
167 | ```
168 |
169 | You should see your LED blink!
170 |
171 | #Further Reading
172 |
173 | * 1 Watch a video about the difference between a compiler and interpreter: https://www.youtube.com/watch?v=_C5AHaS1mOA
174 | * 2 "PLL" stands for "Phase-locked Loop", read more about it here: http://en.wikipedia.org/wiki/Phase-locked_loop
175 |
--------------------------------------------------------------------------------
/documentation/images/i-can-spin-a-rainbow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/documentation/images/i-can-spin-a-rainbow.png
--------------------------------------------------------------------------------
/documentation/images/layout-diving-into-multicore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/documentation/images/layout-diving-into-multicore.png
--------------------------------------------------------------------------------
/documentation/images/layout-your-first-spin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/documentation/images/layout-your-first-spin.png
--------------------------------------------------------------------------------
/documentation/images/propeller-hat-eeprom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/documentation/images/propeller-hat-eeprom.png
--------------------------------------------------------------------------------
/documentation/images/propeller-hub-cog-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/documentation/images/propeller-hub-cog-diagram.png
--------------------------------------------------------------------------------
/documentation/images/propeller-ide-download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/documentation/images/propeller-ide-download.png
--------------------------------------------------------------------------------
/documentation/images/propeller-ide-serial-terminal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/documentation/images/propeller-ide-serial-terminal.png
--------------------------------------------------------------------------------
/examples/Diving-into-multicore.spin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/examples/Diving-into-multicore.spin
--------------------------------------------------------------------------------
/examples/My-first-PASM.spin:
--------------------------------------------------------------------------------
1 | CON
2 | _CLKMODE = xtal1 + pll16x
3 | _XINFREQ = 6_000_000
4 |
5 | MY_LED_PIN = 0
6 |
7 | PUB main
8 | cognew(@blink, 0) ' Start a Cog with our assembly routine, no stack
9 | ' is required since PASM requires we explicitly
10 | ' assign and use memory locations within the Cog/Hub
11 | DAT
12 | org 0
13 | blink mov dira, Pin ' Set our Pin to an output
14 | rdlong Delay, #0 ' Prime the Delay variable with memory location 0
15 | ' this is where the Propeller stores the CLKFREQ variable
16 | ' which is the number of clock ticks per second
17 | mov Time, cnt ' Prime our timer with the current value of the system counter
18 | add Time, #9 ' Add a minimum delay ( more on this below )
19 | :loop waitcnt Time, Delay ' Start waiting
20 | xor outa, Pin ' Toggle our output pin with "xor"
21 | jmp #:loop ' Jump back to the beginning of our loop
22 |
23 | Pin long |< MY_LED_PIN ' Encde MY_LED_PIN to a bit mask
24 | Delay res 1
25 | Time res 1
26 | fit
27 |
--------------------------------------------------------------------------------
/examples/Passing-params-in-PASM.spin:
--------------------------------------------------------------------------------
1 | CON
2 | _CLKMODE = xtal1 + pll16x
3 | _XINFREQ = 6_000_000
4 |
5 | VAR
6 | long MY_PIN_1, MY_PIN_2 ' These will appear next to each other in memory
7 |
8 | PUB main
9 | MY_PIN_1 := |< 0 ' Set our first pin to a bitmask for A0
10 | MY_PIN_2 := |< 1 ' And our second for A1
11 | cognew(@blink, @MY_PIN_1) ' Supply the address of the first parameter
12 |
13 | DAT
14 | org 0
15 | blink mov addr, par ' Load our address from the boot param
16 | rdlong Pn, addr ' Read the first pin number
17 | add addr, #4 ' Increment addr by 1 byte
18 | rdlong Pn2, addr ' Read the second pin number
19 |
20 | or dira, Pn ' Set up pins as outputs
21 | or dira, Pn2 ' It's good to do stuff while we're waiting
22 | ' for the Hub to come back around, since we
23 | ' only just synced for a rdbyte!
24 |
25 | rdlong Delay, #0 ' Prepare the delay
26 | mov Time, cnt ' Prep the wait time
27 | add Time, #9 ' Add the minimum wait time
28 |
29 | :loop waitcnt Time, Delay ' Start blinking!
30 | xor outa, Pn
31 | xor outa, Pn2
32 | jmp #:loop
33 |
34 | Pn res 1 ' Store our first LED pin
35 | Pn2 res 1 ' Store our second LED pin
36 | Addr res 1 ' Store our parameter address
37 | Delay res 1 ' Store the delay increment
38 | Time res 1 ' Store the current time for wait
39 | fit
40 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | #Documentation Source
2 |
3 | The files you find here are complete examples from the Propeller HAT documentation.
4 |
5 | To upload one to your Propeller HAT you must first compile it into a binary, like so:
6 |
7 | ```bash
8 | openspin Diving-into-multicore.spin
9 | ```
10 |
11 | Then you can load it with propman, like so:
12 |
13 | ```bash
14 | propman Diving-into-multicore.binary
15 | ```
16 |
--------------------------------------------------------------------------------
/examples/Signalling-with-pins.spin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/examples/Signalling-with-pins.spin
--------------------------------------------------------------------------------
/examples/Sweeping-LEDs-PASM.spin:
--------------------------------------------------------------------------------
1 | CON
2 | _CLKMODE = xtal1 + pll16x
3 | _XINFREQ = 6_000_000
4 |
5 | MY_LED_PIN = 2
6 |
7 | VAR
8 | long START_PIN, END_PIN ' These will appear next to each other in memory
9 |
10 | PUB main
11 | START_PIN := |< 0
12 | END_PIN := |< 8
13 |
14 | cognew(@sweep, @START_PIN)
15 |
16 | DAT
17 |
18 | org 0
19 | sweep mov Addr, par ' Load parameter into Addr
20 | rdlong S_Pin, Addr ' Read START_PIN variabe from Hub
21 | add Addr, #4 ' Increment address pointer by 1 byte
22 | rdlong E_Pin, Addr ' Read END_PIN variable from Hub
23 |
24 | mov C_Pin, S_Pin ' Start at the START_PIN
25 |
26 | rdlong Delay, #0 ' Read clkfreq ( ticks per second )
27 | shr Delay, #4 ' Shift delay right 4 ( divide by 16 )
28 |
29 | mov Time, cnt ' Read current system counter state
30 | add Time, #9
31 |
32 | :loop waitcnt Time, Delay
33 | or dira, C_Pin
34 | xor outa, C_Pin
35 | rol C_Pin, #1 ' Rotate C_Pin left one place
36 | cmp C_Pin, E_Pin wz ' Compare C_Pin to END_PIN
37 | if_e mov C_Pin, S_Pin ' Return to the START_PIN
38 | jmp #:loop ' Loop!
39 |
40 | Addr res 1
41 | S_Pin res 1
42 | E_Pin res 1
43 | C_Pin res 1
44 | Delay res 1
45 | Time res 1
46 | fit
47 |
48 |
49 |
--------------------------------------------------------------------------------
/examples/Your-first-SPIN-program.spin:
--------------------------------------------------------------------------------
1 | {{
2 | Your first SPIN Program!
3 | Accompanying tutorial: https://github.com/pimoroni/propeller-hat/blob/master/documentation/Your-first-SPIN-program.md
4 |
5 | This program blinks pin A0 on the Propeller HAT board.
6 | }}
7 | CON
8 | _CLKMODE = xtal1 + pll16x ' Use an external crystal multplied 16x
9 | _XINFREQ = 6_000_000 ' Our external crystal is 6Mhz
10 |
11 | MY_LED_PIN = 0 ' Use pin A0
12 |
13 | PUB main
14 | DIRA[MY_LED_PIN] := 1 ' Set the LED pin to an output
15 |
16 | repeat ' Repeat forever
17 | OUTA[MY_LED_PIN] := 1 ' Turn the LED on
18 | waitcnt(cnt + clkfreq) ' Wait 1 second
19 | ' cnt is the clock tick counter,
20 | ' clkfreq is the number of clock ticks in a second
21 | DIRA[MY_LED_PIN] := 0 ' Turn the LED off
22 |
23 |
--------------------------------------------------------------------------------
/hardware/Propeller-HAT-schematic.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/hardware/Propeller-HAT-schematic.pdf
--------------------------------------------------------------------------------
/hardware/Propeller-HAT.fzpz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/hardware/Propeller-HAT.fzpz
--------------------------------------------------------------------------------
/hardware/README.md:
--------------------------------------------------------------------------------
1 | # Propeller HAT Hardware
2 |
3 | ## License
4 |
5 | 
6 |
7 | Propeller HAT is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.: http://creativecommons.org/licenses/by-sa/4.0/
8 |
9 | #### This license covers:
10 |
11 | * Propeller HAT board design and schematic layout - Propeller-HAT.brd, Propeller-HAT.sch
12 |
13 | #### This license does *not* cover:
14 |
15 | * The Parallax Propeller chip itself1
16 | * Supporting ICs and components used on the Propeller HAT
17 | * Logos or silkscreen artwork
18 |
19 | 1 The Parallax Propeller is licensed under the GNU GPL 3.0, you can find the HDL source to the microcontroller, plus more information, here: http://www.parallax.com/microcontrollers/propeller-1-open-source
20 |
21 | #### This license allows you to:
22 |
23 | * Share — copy and redistribute the material in any medium or format
24 | * Adapt — remix, transform, and build upon the material for any purpose, even commercially.
25 |
26 | #### However, you must:
27 |
28 | * give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests we endorse you or your use.
29 | * distribute your contributions under the same license as the original if you remix, transform, or build upon this material.
30 |
31 | ## Pinout
32 |
33 | All Propeller IO is broken out in the horizontal pin headers. Note: The TX/RX pins, while available to the IC as general purpose IO pins normally, are tied to the GPIO of the Raspberry Pi and thus cannot be used.
34 |
35 | Pins A29 and A28 are EEPROM SDA and SCL respectively. A 24LC512-I/P1 EEPROM is recommended, and will require 10K pullup resistors. Once added, the Propeller will allow uploads to EEPROM and will load its contents upon boot.
36 |
37 | ## Bill Of Materials
38 |
39 | * 1 x P8X32A-Q44 - QFP Parallax Propeller IC
40 | * 1 x ABLS3-6.000MHZ-D4Y-T - 6Mhz Crystal Oscillator
41 | * 1 x AP7333-__SRG - 300mA, 3.3V Voltage Regulator
42 | * 1 x EEPROM - for Raspberry HAT compatibility
43 | * 1 x 40PIN Low Profile Female SMD Header
44 | * 1 x 10K Resistor R0603
45 | * 2 x 4.7K Resistor R0603
46 | * 1 x 1K Resistor R0603
47 | * 4 x 0.1uF Capacitor C0603K
48 | * 2 x 1uF Capacitor C0603K
49 |
50 | ## Crystal
51 |
52 | 6Mhz was chosen for a conservative overclock, but should be well within the range of values a P8X32A chip can tolerate under normal hobbyist operating conditions. PropellerHAT can operate on a 4Mhz-8Mhz variant of the ABLS3 Crystal. Typical clock speeds at a PLL of 16 to 2x include:
53 |
54 | | Xin | 16x | 8x | 4x | 2x |
55 | |------|---------|-------|-------|-------|
56 | | 8Mhz | 128Mhz* | 64Mhz | 32Mhz | 16Mhz |
57 | | 6Mhz | 96Mhz | 48Mhz | 24Mhz | 12Mhz |
58 | | 5Mhz | 80Mhz | 40Mhz | 20Mhz | 10Mhz |
59 |
60 | *Speed not supported or recommended.
61 |
62 | * [ABLS3 Crystal Oscillator datasheet](/datasheets/Crystal-OSC-ABLS3-25529.pdf)
63 |
64 | * 1 http://uk.mouser.com/ProductDetail/Microchip-Technology/24LC512-I-P/?qs=JmwSjbzn2OL8zYUOM6epRw%3D%3D
65 |
--------------------------------------------------------------------------------
/propeller-hat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/propeller-hat.jpg
--------------------------------------------------------------------------------
/propeller-ide-download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/propeller-ide-download.png
--------------------------------------------------------------------------------
/software/README.md:
--------------------------------------------------------------------------------
1 | Raspberry Pi Propeller HAT
2 | ==========================
3 |
4 | The tools provided in this library are specifically designed
5 | for the Raspberry Pi Propeller HAT and may require adaptation
6 | to function with any other platforms.
7 |
8 | The PropellerHAT library serves a dual purpose, as a Python
9 | binary uploader for the Propeller and as a library which can
10 | be imported into your Python modules to prepare the Propeller for
11 | specific use-cases such as emulating an IO expander.
12 |
--------------------------------------------------------------------------------
/software/p1load/README.md:
--------------------------------------------------------------------------------
1 | #p1load
2 |
3 | p1load has now been superseded by propman, which is installed by the Propeller IDE since version 0.30.0
4 |
5 | There is therefore little reason to use p1load as an alternative. However, it is kept in this repository in case it could be useful to users who must stick to using an older version of the IDE, or prefer not to install the IDE or compile propman from source.
6 |
7 | To use, simply run:
8 |
9 | ```bash
10 | ./install
11 | ```
12 | then:
13 |
14 | ```bash
15 | p1load binary_file.binary
16 | ```
17 |
--------------------------------------------------------------------------------
/software/p1load/install:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | LOAD_DIR=/usr/share/propelleride/bin/p1load
3 |
4 | sudo cp p1load $LOAD_DIR
5 | sudo chown root $LOAD_DIR
6 | sudo chmod 4755 $LOAD_DIR
7 | sudo ln -s $LOAD_DIR /usr/bin/p1load
8 |
--------------------------------------------------------------------------------
/software/p1load/p1load:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/software/p1load/p1load
--------------------------------------------------------------------------------
/software/python/library/CHANGELOG.txt:
--------------------------------------------------------------------------------
1 | 1.0.1
2 | -----
3 |
4 | * Ready for Propeller HAT launch
5 |
6 |
--------------------------------------------------------------------------------
/software/python/library/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Parallax Propeller code uploader
2 | Copyright (C) 2007 Remy Blank
3 |
4 | This file is part of PropTools.
5 |
6 | This program is free software; you can redistribute it and/or modify it
7 | under the terms of the GNU General Public License as published by the
8 | Free Software Foundation, version 2.
9 |
10 | License: http://www.gnu.org/licenses/gpl-2.0.html
11 |
12 | This program is distributed in the hope that it will be useful, but
13 | WITHOUT ANY WARRANTY; without even the implied warranty of
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 | Public License for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program; if not, write to the Free Software Foundation,
19 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20 |
21 | Modified January 2015 by Phil Howard
22 | Modifications include support for the Raspberry Pi, mainly a
23 | GPIO-based reset mechanism for GPIO-connected Propeller boards.
24 |
25 | Various tweaks to the code have also been made both for general clarity
26 | and to bring it closer to the Python PEP 8 style guidelines.
27 |
28 | I have also extensively commented appropriate areas and attempted
29 | to explain in sufficient detail the workings of the protocol.
30 |
--------------------------------------------------------------------------------
/software/python/library/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include CHANGELOG.txt
2 | include LICENSE.txt
3 | include README.txt
4 | include setup.py
5 | include p1/*
6 |
--------------------------------------------------------------------------------
/software/python/library/README.md:
--------------------------------------------------------------------------------
1 | Python PropellerHAT Code Uploader
2 | =================================
3 |
4 | Code uploader and Python bindings for the Propeller P8X32A Multi-core Microprocessor.
5 |
6 | Uploader works as a standalone tool, run with:
7 |
8 | sudo python -m p1.loader
9 |
10 | Credits
11 | =======
12 |
13 | Thanks to Remy Blank for the original code, released on the Parallax
14 | forums in 2007. I have taken pains to credit him appropriately.
15 |
16 | http://forums.parallax.com/showthread.php/90707-Propeller-development-for-non-Windows-users
17 |
18 | Although I have changed the code quite significantly to fix performance
19 | issues on the Raspberry Pi, and address GPIO reset, much of his work
20 | remains in-tact and this code should be portable.
21 |
22 | Thanks also to Jeff Martin who helped me understand the loader protocol
23 | and whose improvements to the upload process I hope to implement soon.
24 |
--------------------------------------------------------------------------------
/software/python/library/README.txt:
--------------------------------------------------------------------------------
1 |
2 | Python PropellerHAT Code Uploader
3 | =================================
4 |
5 | Code uploader and Python bindings for the Propeller P8X32A Multi-core Microprocessor.
6 |
7 | Uploader works as a standalone tool, run with:
8 |
9 | sudo python -m p1.loader
10 |
11 | Credits
12 | =======
13 |
14 | Thanks to Remy Blank for the original code, released on the Parallax
15 | forums in 2007. I have taken pains to credit him appropriately.
16 |
17 | http://forums.parallax.com/showthread.php/90707-Propeller-development-for-non-Windows-users
18 |
19 | Although I have changed the code quite significantly to fix performance
20 | issues on the Raspberry Pi, and address GPIO reset, much of his work
21 | remains in-tact and this code should be portable.
22 |
23 | Thanks also to Jeff Martin who helped me understand the loader protocol
24 | and whose improvements to the upload process I hope to implement soon.
25 |
--------------------------------------------------------------------------------
/software/python/library/p1/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = '1.0.1'
2 |
--------------------------------------------------------------------------------
/software/python/library/p1/io.py:
--------------------------------------------------------------------------------
1 | import os
2 | from sys import exit, version_info
3 |
4 | try:
5 | import smbus
6 | except ImportError:
7 | if version_info[0] < 3:
8 | exit("This library requires python-smbus\nInstall with: sudo apt-get install python-smbus")
9 | elif version_info[0] == 3:
10 | exit("This library requires python3-smbus\nInstall with: sudo apt-get install python3-smbus")
11 |
12 | import p1.loader
13 |
14 |
15 | binary = [0x0,0xd8,0xb8,0x5,0x6f,0xbf,0x10,0x0,0x7c,0x2,0x90,0x3,0x1c,0x0,0x98,0x3,0x54,0x0,0x2,0x1,0xc,0x0,0x4,0x0,0x54,0x0,0x4,0x0,0x1,0x38,0x1a,0x38,0x1b,0x38,0x17,0x6,0x2,0x1,0x35,0x65,0x35,0x64,0x3d,0xb6,0x35,0x64,0x3d,0xb4,0x35,0x37,0x24,0x66,0x2,0x72,0x35,0x65,0x0,0x64,0x37,0x4,0xec,0x6,0x2,0x9,0x36,0xfc,0x64,0x3d,0xb6,0x0,0x64,0x6,0x2,0x9,0x36,0xfc,0x64,0x3d,0xb4,0x1,0x64,0x37,0x5,0xec,0x64,0x3d,0x92,0x6,0x2,0xa,0x35,0x38,0x1b,0x66,0x2,0x58,0x4,0x54,0x32,0x0,0x18,0x2,0xc,0x0,0xac,0x1,0x0,0x0,0xc5,0x1,0x0,0x0,0xd2,0x1,0x0,0x0,0xd6,0x1,0x0,0x0,0xe2,0x1,0x0,0x0,0xf5,0x1,0x0,0x0,0xf8,0x1,0x0,0x0,0xfe,0x1,0x0,0x0,0x5,0x2,0x0,0x0,0xa,0x2,0x0,0x0,0xf,0x2,0x4,0x0,0xf0,0xd1,0xbc,0xa0,0x68,0xca,0xbc,0xa0,0x4,0xd0,0xfc,0x80,0x68,0xc4,0xbc,0x0,0x1,0xc4,0xfc,0x2c,0x1,0xd0,0xfc,0x80,0x68,0xd2,0xbc,0x0,0x1,0xbe,0xfc,0xa0,0x69,0xbe,0xbc,0x2c,0x1,0xd0,0xfc,0x80,0x68,0xd2,0xbc,0x0,0x1,0xc0,0xfc,0xa0,0x69,0xc0,0xbc,0x2c,0x1,0xd0,0xfc,0x80,0x68,0xc6,0xbc,0xa0,0x5f,0xc2,0xbc,0xa0,0x60,0xc2,0xbc,0x68,0x61,0xc2,0x3c,0xf0,0x60,0xc0,0x3c,0xf4,0xf2,0xbf,0x3c,0x61,0x11,0x0,0x4c,0x5c,0x31,0x8e,0xfc,0x5c,0x66,0xd0,0xbc,0xa0,0xfe,0xd0,0xfc,0x60,0x62,0xd0,0x3c,0x86,0x11,0x0,0x54,0x5c,0x59,0xbc,0xfc,0x5c,0x1,0xcc,0x7c,0x61,0x21,0x0,0x4c,0x5c,0x4a,0xb0,0xfc,0x5c,0x1,0xc8,0xfc,0x80,0x1d,0x0,0x4c,0x5c,0x11,0x0,0x7c,0x5c,0x65,0xd0,0xbc,0x8,0x1,0xd2,0xfc,0xa0,0x63,0xc8,0xbc,0xa0,0x31,0x8e,0xfc,0x5c,0x66,0xc8,0xbc,0x80,0x66,0xd2,0xbc,0x2c,0x59,0xbc,0xfc,0x5c,0x69,0xd0,0xbc,0x68,0x31,0x8e,0xfc,0x5c,0x64,0xcc,0x3c,0x0,0x1,0xc8,0xfc,0x80,0x69,0xd0,0xbc,0x68,0x65,0xd0,0x3c,0x8,0x1,0xd2,0xfc,0x2c,0x59,0xbc,0xfc,0x5c,0x29,0x0,0x7c,0x5c,0x7,0xce,0xfc,0xa0,0x0,0xcc,0xfc,0xa0,0x5f,0xbe,0x3c,0xf4,0x5f,0xbe,0x3c,0xf0,0xf2,0xc1,0x3c,0x61,0x1,0xcc,0xfc,0x34,0x3d,0x0,0x70,0x5c,0xf2,0xbf,0x3c,0x62,0x42,0x0,0x68,0x5c,0xf2,0xc1,0x3c,0x62,0x48,0x0,0x54,0x5c,0x38,0x0,0x7c,0x5c,0xf2,0xbf,0x3c,0x62,0x42,0x0,0x68,0x5c,0xf2,0xc1,0x3c,0x62,0x15,0x0,0x68,0x5c,0x3d,0x0,0x7c,0x5c,0x5f,0xbe,0x3c,0xf4,0x5f,0xbe,0x3c,0xf0,0xf2,0xc1,0x3c,0x61,0x1,0xcc,0xfc,0x34,0x42,0xce,0xfc,0xe4,0x0,0x0,0x7c,0x5c,0x65,0xd0,0x3c,0x8,0x11,0x0,0x7c,0x5c,0x8,0xce,0xfc,0xa0,0x64,0xcc,0xbc,0x0,0x18,0xcc,0xfc,0x2c,0x5f,0xbe,0x3c,0xf4,0x1,0xcc,0xfc,0x2d,0x60,0xec,0xbf,0x74,0x5f,0xbe,0x3c,0xf0,0x5f,0xbe,0x3c,0xf4,0x4d,0xce,0xfc,0xe4,0x60,0xec,0xbf,0x64,0x5f,0xbe,0x3c,0xf4,0x5f,0xbe,0x3c,0xf0,0xf2,0xc1,0x3c,0x61,0x5f,0xbe,0x3c,0xf4,0x0,0x0,0x7c,0x5c,0x5f,0xbe,0x3c,0xf4,0x60,0xec,0xbf,0x68,0x5f,0xbe,0x3c,0xf0,0x5f,0xbe,0x3c,0xf4,0x60,0xec,0xbf,0x64,0x0,0x0,0x7c,0x5c,0x1,0x5,0x2,0x6c,0x89,0x4,0x64,0x89,0x5,0x68,0x89,0x6,0x34,0xc7,0x30,0x43,0x28,0x36,0xec,0x8a,0x81,0x7,0x80,0x61,0x32,0x88,0x81,0x7,0xa,0x7,0x8a,0x81,0x7,0x98,0x36,0xed,0x21,0x32,0x8b,0x7,0x33,0x32,0x40,0xf1,0x36,0xed,0x61,0x40,0x60,0xf3,0xe7,0xe8,0x41,0x32,0x64,0xf3,0x40,0xe8,0xa,0xa,0x40,0x64,0xf3,0xe7,0xe8,0x41,0x64,0x98,0x7,0x33,0x34,0x33,0x32,0x40,0x33,0x32,0x64,0xf3,0x40,0xe8,0x33,0x32,0x40,0x64,0xf3,0xe7,0xe8,0x41,0x32,0x64,0x98,0x7,0x33,0x32,0x68,0x64,0x99,0x7,0x32,0x42,0x18,0x8b,0x7,0x35,0x37,0x7,0x18,0x32]
16 |
17 | print('Setting up Propeller HAT')
18 | l = p1.loader.Loader('/dev/ttyAMA0',17)
19 | l.upload(code=''.join(map(chr,binary)),progress=p1.loader.print_status)
20 |
21 | i2c = smbus.SMBus(1)
22 |
23 | addr = 0x17
24 |
25 | OUTPUT = 1
26 | OUT = 1
27 | INPUT = 0
28 | IN = 0
29 | HIGH = 1
30 | LOW = 0
31 |
32 | def setup(address):
33 | global addr
34 | addr = address
35 |
36 | def mode(pin,mode):
37 | i2c.write_byte_data(addr, pin+32, mode)
38 |
39 | def write(pin,out):
40 | i2c.write_byte_data(addr, pin, out)
41 |
42 | def read(pin):
43 | return i2c.read_byte_data(addr, pin+64)
44 |
--------------------------------------------------------------------------------
/software/python/library/p1/pwm.py:
--------------------------------------------------------------------------------
1 | import struct
2 | from sys import exit
3 |
4 | try:
5 | import serial
6 | except ImportError:
7 | exit("This library requires the serial module\nInstall with: sudo pip install pyserial")
8 |
9 | import p1.loader
10 |
11 |
12 | binary=[
13 | 0x0,0xd8,0xb8,0x5,0x6f,0x2d,0x10,0x0,0x98,0xb,0xfc,0xb,0x20,0x0,0x20,0xc,0xc,0x1,0x2,0x2,0x10,0x0,0x20,0x0,0xc,0x1,0x0,0x0,0xbc,0x3,0x48,0x0,0x1,0x37,0x24,0x38,0x1e,0x35,0x3a,0x1,0xc2,0x0,0x6,0x2,0x1,0x1,0x6,0x3,0x2,0x3f,0x91,0x35,0xc0,0xec,0x23,0x1,0x38,0xe1,0x6,0x2,0x7,0x0,0x6,0x2,0x6,0x37,0x27,0xfc,0x0,0x6,0x2,0x6,0x37,0x27,0xfc,0xf0,0xa,0x80,0xc8,0x0,0x6,0x2,0x6,0x69,0x68,0x35,0xfc,0xa,0x9,0x1,0x38,0xe1,0x6,0x2,0x7,0x4,0x80,0xb5,0x68,0x36,0xfc,0xa,0x37,0x0,0x6,0x2,0x6,0x65,0x64,0x38,0x1e,0x36,0xed,0xfa,0xa,0x5,0x38,0x1e,0x36,0xed,0x65,0x0,0x6,0x2,0x6,0x71,0x0,0x6,0x2,0x6,0x37,0x2,0xe3,0x0,0x6,0x2,0x6,0xec,0x75,0x74,0x38,0x64,0xfa,0xa,0x3,0x38,0x64,0x75,0x1,0x64,0x70,0x74,0x6,0x3,0x4,0x4,0x80,0x79,0x68,0x37,0x0,0xfc,0xa,0x28,0x0,0x6,0x2,0x6,0x65,0x64,0x38,0x1e,0x36,0xed,0xfa,0xa,0x5,0x38,0x1e,0x36,0xed,0x65,0x0,0x6,0x2,0x6,0x37,0x2,0xe3,0x0,0x6,0x2,0x6,0xec,0x79,0x1,0x64,0x78,0x6,0x3,0x5,0x4,0x80,0x4b,0x68,0x37,0x21,0xfc,0xa,0x37,0x0,0x6,0x2,0x6,0x65,0x64,0x38,0x1e,0x36,0xed,0xfa,0xa,0x5,0x38,0x1e,0x36,0xed,0x65,0x0,0x6,0x2,0x6,0x37,0x2,0xe3,0x0,0x6,0x2,0x6,0xec,0x7d,0x0,0x6,0x2,0x6,0x37,0x2,0xe3,0x0,0x6,0x2,0x6,0xec,0xcd,0x20,0x1,0x64,0x7c,0xcc,0x20,0x6,0x3,0x6,0x4,0xe,0x68,0x37,0x27,0xfc,0xa,0x8,0x1,0x6,0x3,0x1,0x1,0x6,0x3,0x2,0x4,0xff,0x23,0x32,0x0,0xb0,0x2,0xc,0x0,0x80,0x1,0x0,0x0,0xa2,0x1,0x0,0x0,0xb0,0x1,0x0,0x0,0xba,0x1,0x0,0x0,0xcd,0x1,0x4,0x0,0xea,0x1,0x0,0x0,0xf6,0x1,0x0,0x0,0x17,0x2,0x0,0x0,0x24,0x2,0x8,0x0,0x70,0x2,0x0,0x0,0x98,0x2,0x0,0x0,0xf0,0xa9,0xbc,0xa0,0x10,0xa8,0xfc,0x80,0x54,0xaa,0xbc,0x8,0x1,0xb2,0xfc,0xa0,0x55,0xb2,0xbc,0x2c,0x4,0xa8,0xfc,0x80,0x54,0xaa,0xbc,0x8,0x1,0xbe,0xfc,0xa0,0x55,0xbe,0xbc,0x2c,0x4,0xa8,0xfc,0x80,0x54,0xae,0xbc,0x8,0x4,0xa8,0xfc,0x80,0x54,0xb0,0xbc,0x8,0x4,0xa8,0xfc,0x80,0x54,0xb4,0xbc,0x8,0x5a,0xc0,0xbc,0xa0,0x10,0xc0,0xfc,0x80,0x4,0xae,0x7c,0x62,0x2,0xae,0x7c,0x61,0x5f,0xe8,0x9b,0x68,0x5f,0xec,0xab,0x68,0x33,0xc8,0xfc,0xa0,0x64,0xbc,0xbc,0x5c,0x1,0xae,0x7c,0x62,0xf2,0xb3,0x3c,0x61,0x16,0x0,0x64,0x5c,0x9,0xb8,0xfc,0xa0,0x58,0xba,0xbc,0xa0,0x1,0xba,0xfc,0x28,0xf1,0xbb,0xbc,0x80,0x58,0xba,0xbc,0x80,0x64,0xbc,0xbc,0x5c,0x5d,0xa8,0xbc,0xa0,0xf1,0xa9,0xbc,0x84,0x0,0xa8,0x7c,0xc1,0x1f,0x0,0x4c,0x5c,0xf2,0xb3,0x3c,0x61,0x1,0xb6,0xfc,0x30,0x1e,0xb8,0xfc,0xe4,0x17,0xb6,0xfc,0x28,0xff,0xb6,0xfc,0x60,0x1,0xae,0x7c,0x62,0xff,0xb6,0xd4,0x6c,0xf0,0xab,0xbc,0x8,0x5a,0xaa,0xbc,0x80,0x55,0xb6,0x3c,0x0,0x5a,0xaa,0xbc,0x84,0x1,0xaa,0xfc,0x80,0xf,0xaa,0xfc,0x60,0xf0,0xab,0x3c,0x8,0x16,0x0,0x7c,0x5c,0x5e,0xc8,0xbc,0x5c,0xf0,0xa9,0xbc,0xa0,0x8,0xa8,0xfc,0x80,0x54,0xaa,0xbc,0x8,0x4,0xa8,0xfc,0x80,0x54,0xac,0xbc,0x8,0x56,0xaa,0x3c,0x86,0x33,0x0,0x68,0x5c,0x60,0xac,0xbc,0x80,0x56,0xc2,0xbc,0x0,0x60,0xac,0xbc,0x84,0x1,0xac,0xfc,0x80,0xf,0xac,0xfc,0x60,0x54,0xac,0x3c,0x8,0x0,0xc3,0xfc,0x68,0x2,0xc2,0xfc,0x2c,0x1,0xc2,0xfc,0x68,0xb,0xc4,0xfc,0xa0,0xf1,0xc7,0xbc,0xa0,0x4,0xae,0x7c,0x62,0x2,0xae,0x7c,0x61,0x1,0xc2,0xe0,0x6c,0x1,0xc2,0xfc,0x29,0x5f,0xe8,0xab,0x70,0x5f,0xec,0x97,0x74,0x58,0xc6,0xbc,0x80,0x5e,0xc8,0xbc,0x5c,0x63,0xa8,0xbc,0xa0,0xf1,0xa9,0xbc,0x84,0x0,0xa8,0x7c,0xc1,0x4d,0x0,0x4c,0x5c,0x46,0xc4,0xfc,0xe4,0x33,0x0,0x7c,0x5c,0x1,0x5,0x2,0x47,0x35,0x37,0x1,0x1a,0x57,0x67,0x37,0x21,0x1e,0x35,0xc0,0x70,0xf6,0xc9,0x20,0x8b,0x28,0xc9,0x24,0x34,0xc7,0x30,0x47,0x28,0x36,0xec,0x42,0x80,0x61,0x32,0x40,0xa,0x5,0x42,0x98,0x36,0xed,0x21,0x47,0x35,0x38,0x9,0x1a,0x32,0x0,0x5,0x4,0x35,0xfe,0xa,0x2,0x4,0x77,0x32,0x62,0x3e,0x48,0x44,0xfb,0xa,0xb,0x48,0x98,0x28,0x61,0x48,0x36,0xec,0x37,0x23,0xe8,0x49,0x32,0x3f,0x91,0x69,0x0,0x5,0x4,0x62,0x80,0x35,0xfe,0x3f,0x91,0x68,0xed,0x35,0xc0,0x39,0x3,0xe8,0xf6,0xf6,0x64,0xfa,0xf2,0xb,0x2,0x4,0x67,0x32,0x0,0x5,0x4,0x62,0x80,0x35,0xf9,0xa,0x2,0x4,0x75,0x32,0x50,0x4c,0x36,0xec,0x37,0x23,0xe8,0xfb,0xb,0x2,0x4,0x74,0x64,0x4c,0x99,0x38,0x4c,0x36,0xec,0x37,0x23,0xe8,0x4d,0x5c,0x37,0x2,0xe8,0xa,0x3,0x1,0x5,0x6,0x32,0x64,0x16,0x8,0x8,0x1,0x66,0xae,0x80,0x5,0x7,0x9,0x78,0x32,0x64,0x37,0x1e,0xfc,0x6d,0x64,0x35,0xf9,0xa,0xa,0x64,0x6c,0xec,0xe9,0x65,0x1,0x38,0x2d,0x5,0x7,0x3b,0x3b,0x9a,0xca,0x0,0x69,0x38,0xa,0x8,0x2d,0x64,0x68,0xfe,0xa,0x16,0x1,0x64,0x68,0xf6,0x38,0x30,0xec,0x6c,0x68,0x36,0xfc,0xf4,0xec,0x5,0x7,0x68,0x66,0x57,0x62,0x1c,0x4,0xc,0x60,0x68,0x36,0xfc,0xf2,0xa,0x5,0x1,0x38,0x30,0x5,0x7,0x38,0xa,0x6a,0x56,0x9,0x53,0x32,0x37,0x2,0x68,0xed,0x37,0x0,0xe3,0x66,0x43,0x68,0x8,0x1b,0x1,0x35,0x39,0x2,0x93,0x37,0x1,0x66,0xc1,0x37,0x23,0xe8,0x38,0x30,0x38,0x39,0x12,0x38,0x41,0x38,0x46,0x12,0xf,0x5,0x7,0x9,0x65,0x32,0x37,0x4,0x68,0xed,0x66,0x43,0x68,0x8,0xd,0x1,0x36,0x66,0xc1,0x36,0xe8,0x38,0x30,0xec,0x5,0x7,0x9,0x73,0x32,0x0,0xcc,0x7,0x9,0x0,0x74,0x6,0x0,0x0,0x77,0x6,0x0,0x0,0x7e,0x6,0x0,0x0,0x99,0x6,0xc,0x0,0x1e,0x7,0x8,0x0,0x49,0x7,0x0,0x0,0xab,0x7,0x0,0x0,0xba,0x7,0x0,0x0,0xf0,0xe1,0xbd,0xa0,0xf0,0xd8,0xbd,0xa0,0x4,0xe0,0xfd,0x80,0xf0,0xda,0xbd,0xa0,0x4,0xe0,0xfd,0x80,0xf0,0xdc,0xbd,0xa0,0x4,0xe0,0xfd,0x80,0xf0,0xde,0xbd,0xa0,0x1,0x28,0xfe,0x85,0xf4,0xe8,0xb2,0x6e,0x34,0x29,0xa2,0xa0,0x54,0x29,0x92,0xa0,0x1,0x2a,0xfe,0x85,0xf5,0xea,0xb2,0x6e,0x35,0x2b,0xa2,0xa0,0x55,0x2b,0x92,0xa0,0x1,0x2c,0xfe,0x85,0xf6,0xec,0xb2,0x6e,0x36,0x2d,0xa2,0xa0,0x56,0x2d,0x92,0xa0,0x1,0x2e,0xfe,0x85,0xf7,0xee,0xb2,0x6e,0x37,0x2f,0xa2,0xa0,0x57,0x2f,0x92,0xa0,0x1,0x30,0xfe,0x85,0xf8,0xf0,0xb2,0x6e,0x38,0x31,0xa2,0xa0,0x58,0x31,0x92,0xa0,0x1,0x32,0xfe,0x85,0xf9,0xf2,0xb2,0x6e,0x39,0x33,0xa2,0xa0,0x59,0x33,0x92,0xa0,0x1,0x34,0xfe,0x85,0xfa,0xf4,0xb2,0x6e,0x3a,0x35,0xa2,0xa0,0x5a,0x35,0x92,0xa0,0x1,0x36,0xfe,0x85,0xfb,0xf6,0xb2,0x6e,0x3b,0x37,0xa2,0xa0,0x5b,0x37,0x92,0xa0,0x1,0x38,0xfe,0x85,0xfc,0xf8,0xb2,0x6e,0x3c,0x39,0xa2,0xa0,0x5c,0x39,0x92,0xa0,0x1,0x3a,0xfe,0x85,0xfd,0xfa,0xb2,0x6e,0x3d,0x3b,0xa2,0xa0,0x5d,0x3b,0x92,0xa0,0x1,0x3c,0xfe,0x85,0xfe,0xfc,0xb2,0x6e,0x3e,0x3d,0xa2,0xa0,0x5e,0x3d,0x92,0xa0,0x1,0x3e,0xfe,0x85,0xff,0xfe,0xb2,0x6e,0x3f,0x3f,0xa2,0xa0,0x5f,0x3f,0x92,0xa0,0x1,0x40,0xfe,0x85,0x0,0x1,0xb3,0x6e,0x40,0x41,0xa2,0xa0,0x60,0x41,0x92,0xa0,0x1,0x42,0xfe,0x85,0x1,0x3,0xb3,0x6e,0x41,0x43,0xa2,0xa0,0x61,0x43,0x92,0xa0,0x1,0x44,0xfe,0x85,0x2,0x5,0xb3,0x6e,0x42,0x45,0xa2,0xa0,0x62,0x45,0x92,0xa0,0x1,0x46,0xfe,0x85,0x3,0x7,0xb3,0x6e,0x43,0x47,0xa2,0xa0,0x63,0x47,0x92,0xa0,0x1,0x48,0xfe,0x85,0x4,0x9,0xb3,0x6e,0x44,0x49,0xa2,0xa0,0x64,0x49,0x92,0xa0,0x1,0x4a,0xfe,0x85,0x5,0xb,0xb3,0x6e,0x45,0x4b,0xa2,0xa0,0x65,0x4b,0x92,0xa0,0x1,0x4c,0xfe,0x85,0x6,0xd,0xb3,0x6e,0x46,0x4d,0xa2,0xa0,0x66,0x4d,0x92,0xa0,0x1,0x4e,0xfe,0x85,0x7,0xf,0xb3,0x6e,0x47,0x4f,0xa2,0xa0,0x67,0x4f,0x92,0xa0,0x1,0x50,0xfe,0x85,0x8,0x11,0xb3,0x6e,0x48,0x51,0xa2,0xa0,0x68,0x51,0x92,0xa0,0x1,0x52,0xfe,0x85,0x9,0x13,0xb3,0x6e,0x49,0x53,0xa2,0xa0,0x69,0x53,0x92,0xa0,0x1,0x54,0xfe,0x85,0xa,0x15,0xb3,0x6e,0x4a,0x55,0xa2,0xa0,0x6a,0x55,0x92,0xa0,0x1,0x56,0xfe,0x85,0xb,0x17,0xb3,0x6e,0x4b,0x57,0xa2,0xa0,0x6b,0x57,0x92,0xa0,0x1,0x58,0xfe,0x85,0xc,0x19,0xb3,0x6e,0x4c,0x59,0xa2,0xa0,0x6c,0x59,0x92,0xa0,0x1,0x5a,0xfe,0x85,0xd,0x1b,0xb3,0x6e,0x4d,0x5b,0xa2,0xa0,0x6d,0x5b,0x92,0xa0,0x1,0x5c,0xfe,0x85,0xe,0x1d,0xb3,0x6e,0x4e,0x5d,0xa2,0xa0,0x6e,0x5d,0x92,0xa0,0x1,0x5e,0xfe,0x85,0xf,0x1f,0xb3,0x6e,0x4f,0x5f,0xa2,0xa0,0x6f,0x5f,0x92,0xa0,0x1,0x60,0xfe,0x85,0x10,0x21,0xb3,0x6e,0x50,0x61,0xa2,0xa0,0x70,0x61,0x92,0xa0,0x1,0x62,0xfe,0x85,0x11,0x23,0xb3,0x6e,0x51,0x63,0xa2,0xa0,0x71,0x63,0x92,0xa0,0x1,0x64,0xfe,0x85,0x12,0x25,0xb3,0x6e,0x52,0x65,0xa2,0xa0,0x72,0x65,0x92,0xa0,0x1,0x66,0xfe,0x85,0x13,0x27,0xb3,0x6e,0x53,0x67,0xa2,0xa0,0x73,0x67,0x92,0xa0,0x74,0xe1,0xbd,0xa0,0x75,0xe1,0xbd,0x68,0x76,0xe1,0xbd,0x68,0x77,0xe1,0xbd,0x68,0x78,0xe1,0xbd,0x68,0x79,0xe1,0xbd,0x68,0x7a,0xe1,0xbd,0x68,0x7b,0xe1,0xbd,0x68,0x7c,0xe1,0xbd,0x68,0x7d,0xe1,0xbd,0x68,0x7e,0xe1,0xbd,0x68,0x7f,0xe1,0xbd,0x68,0x80,0xe1,0xbd,0x68,0x81,0xe1,0xbd,0x68,0x82,0xe1,0xbd,0x68,0x83,0xe1,0xbd,0x68,0x84,0xe1,0xbd,0x68,0x85,0xe1,0xbd,0x68,0x86,0xe1,0xbd,0x68,0x87,0xe1,0xbd,0x68,0x88,0xe1,0xbd,0x68,0x89,0xe1,0xbd,0x68,0x8a,0xe1,0xbd,0x68,0x8b,0xe1,0xbd,0x68,0x8c,0xe1,0xbd,0x68,0x8d,0xe1,0xbd,0x68,0x8e,0xe1,0xbd,0x68,0x8f,0xe1,0xbd,0x68,0x90,0xe1,0xbd,0x68,0x91,0xe1,0xbd,0x68,0x92,0xe1,0xbd,0x68,0x93,0xe1,0xbd,0x68,0xf0,0xe8,0xbf,0xa0,0xec,0xe0,0xbd,0xa,0x8,0x0,0x68,0x5c,0x1,0xe0,0x7d,0x6e,0xb5,0x0,0x68,0x5c,0x2,0xe0,0x7d,0x6e,0xc0,0x0,0x68,0x5c,0x3,0xe0,0x7d,0x6e,0xca,0x0,0x68,0x5c,0x4,0xe0,0x7d,0x6e,0xd9,0x0,0x68,0x5c,0xec,0xd4,0x3d,0x8,0x8,0x0,0x7c,0x5c,0xed,0xe2,0xbd,0x8,0xee,0xe4,0xbd,0x8,0x34,0xe3,0xfd,0x80,0xf1,0x7c,0xbd,0x54,0xef,0xe6,0xbd,0x8,0x20,0xe2,0xfd,0x80,0xf1,0x7a,0xbd,0x54,0xec,0xd4,0x3d,0x8,0xf2,0x0,0xbc,0xa0,0xf3,0x0,0xbc,0xa0,0x8,0x0,0x7c,0x5c,0xed,0xe2,0xbd,0x8,0xee,0xe4,0xbd,0x8,0x1,0xe0,0xfd,0xa0,0xf1,0xe0,0xbd,0x2c,0xec,0xd4,0x3d,0x8,0x1,0xe4,0x7d,0x62,0x0,0x0,0x0,0x0,0xf0,0xec,0x97,0x68,0xf0,0xec,0xab,0x64,0x8,0x0,0x7c,0x5c,0xed,0xe2,0xbd,0x8,0xee,0xe4,0xbd,0x8,0xf1,0xe0,0xbd,0xa0,0x2,0xe0,0xfd,0x2c,0x9,0xe0,0xfd,0x80,0xf0,0xac,0xbd,0x54,0x0,0x0,0x0,0x0,0xe9,0xe0,0xbd,0xa0,0x1,0xe4,0x7d,0x6e,0xe7,0xe0,0xa9,0xa0,0x2,0xe4,0x7d,0x6e,0xe8,0xe0,0xa9,0xa0,0xf0,0x0,0xbc,0x58,0xec,0xd4,0x3d,0x8,0x8,0x0,0x7c,0x5c,0xed,0xe0,0xbd,0x8,0x14,0xe1,0xfd,0x80,0xf0,0xba,0xbd,0x50,0x0,0x0,0x0,0x0,0x0,0xe0,0xbd,0xa0,0xef,0xd6,0xbd,0x8,0xeb,0xe0,0xbd,0x80,0xee,0xd6,0xbd,0x8,0x14,0xd7,0xfd,0x80,0xeb,0xc8,0xbd,0x54,0x0,0x0,0x0,0x0,0xf0,0x0,0xbc,0xa0,0xec,0xd4,0x3d,0x8,0x8,0x0,0x7c,0x5c,0xd1,0x0,0x0,0x0,0xc9,0x0,0x0,0x0,0xdd,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x21,0x32,0x34,0xc7,0x24,0x47,0x28,0x41,0x32,0x6c,0x39,0x3,0xe8,0xf4,0x39,0x20,0x8,0xf6,0x6d,0x64,0x49,0x68,0x4d,0x6c,0x51,0x37,0x1,0x45,0x44,0x35,0xfc,0xb,0x2,0x4,0x79,0x32,0x6c,0x35,0xfb,0xa,0x80,0x79,0x68,0x35,0xfc,0xa,0xb,0x1,0x64,0x37,0x0,0x5,0x8,0x1,0x64,0x36,0x5,0x7,0x68,0x38,0x64,0xfc,0xa,0xa,0x1,0x64,0x36,0x5,0x8,0x1,0x64,0x36,0x5,0x7,0x68,0x35,0xfb,0x68,0x38,0x64,0xfb,0xf0,0xa,0x80,0x4c,0x6c,0x39,0x3,0xe8,0xf4,0x39,0x20,0x8,0xf6,0x71,0x68,0x70,0xf4,0x38,0x64,0xf6,0x75,0x70,0x74,0xed,0x79,0x74,0x35,0xfc,0xa,0x5,0x1,0x64,0x36,0x5,0x8,0x78,0x35,0xfc,0xa,0x6,0x1,0x64,0x37,0x0,0x5,0x8,0x74,0x35,0xfc,0x78,0x35,0xfc,0xf0,0xa,0x5,0x1,0x64,0x35,0x5,0x7,0x74,0x35,0xfb,0x78,0x35,0xfb,0xf2,0xa,0xb,0x1,0x64,0x74,0x78,0x5,0x6,0x1,0x64,0x35,0x5,0x8,0x4,0x5,0x1,0x64,0x35,0x5,0x7,0x32,0x68,0x35,0xfb,0xa,0x20,0x68,0x39,0x3,0xe8,0xf4,0x39,0x20,0x8,0xf6,0x6d,0x39,0x4e,0x20,0x68,0xed,0x39,0x3,0xe8,0xf4,0x39,0x20,0x8,0xf6,0x71,0x1,0x64,0x6c,0x70,0x5,0x6,0x4,0x5,0x1,0x64,0x35,0x5,0x7,0x32,0x68,0x35,0xfc,0x6c,0x35,0xfc,0xf0,0xa,0x5,0x1,0x64,0x35,0x5,0x7,0x68,0x35,0xfc,0xa,0xb,0x1,0x64,0x37,0x0,0x5,0x8,0x1,0x64,0x36,0x5,0x7,0x6c,0x35,0xfc,0xa,0xa,0x1,0x64,0x36,0x5,0x8,0x1,0x64,0x36,0x5,0x7,0x68,0x35,0xfc,0x6c,0x35,0xfc,0xf0,0xa,0x5,0x1,0x64,0x35,0x5,0x7,0x68,0x35,0xfb,0x6c,0x35,0xfb,0xf0,0xa,0x1d,0x64,0x49,0x68,0x36,0xed,0x4d,0x6c,0x36,0xed,0x51,0x36,0x45,0x44,0x35,0xfc,0xb,0x2,0x4,0x79,0x1,0x64,0x36,0x5,0x7,0x1,0x64,0x35,0x5,0x8,0x32,0x64,0x49,0x68,0x4d,0x37,0x0,0x45,0x44,0x35,0xfc,0xb,0x2,0x4,0x79,0x32,0x64,0x49,0x68,0x4d,0x37,0x21,0x45,0x44,0x35,0xfc,0xb,0x2,0x4,0x79,0x32,0x0,0x0,0x0
14 | ]
15 |
16 | print('Setting up Propeller HAT')
17 | l = p1.loader.Loader('/dev/ttyAMA0',17)
18 | l.upload(code=''.join(map(chr,binary)),progress=p1.loader.print_status)
19 |
20 | dev = serial.Serial('/dev/ttyAMA0',baudrate=115200,timeout=0)
21 |
22 | CMD_FW = 0x00
23 | CMD_DUTY = 0x01
24 | CMD_SERVO = 0x02
25 | CMD_PULSE = 0x03
26 | CMD_RESET = 0xff
27 |
28 | def _write(arr):
29 | dev.write(''.join(chr(x) for x in arr))
30 |
31 | def _to_bytes(num):
32 | return list(ord(x) for x in list(struct.pack('>H',num)))
33 |
34 | def duty(pin, duty, freq):
35 | _write([0xff,0xff,CMD_DUTY,pin,duty] + list(ord(x) for x in list(struct.pack('>H',freq))))
36 |
37 | def pulse(pin, on_time, off_time):
38 | _write([0xff,0xff,CMD_PULSE,pin] + _to_bytes(on_time) + _to_bytes(off_time))
39 |
40 | def servo(pin, pulse):
41 | _write([0xff,0xff,CMD_SERVO,pin] + _to_bytes(pulse))
42 |
--------------------------------------------------------------------------------
/software/python/library/p1/serialio.py:
--------------------------------------------------------------------------------
1 | import atexit
2 | import threading
3 | from sys import exit
4 |
5 | try:
6 | import serial
7 | except ImportError:
8 | exit("This library requires the serial module\nInstall with: sudo pip install pyserial")
9 |
10 | import p1.loader
11 |
12 |
13 | class StoppableThread(threading.Thread):
14 | """Basic Stoppable Thread Wrapper
15 |
16 | Adds event for stopping the execution
17 | loop and exiting cleanly."""
18 | def __init__(self):
19 | threading.Thread.__init__(self)
20 | self.stop_event = threading.Event()
21 | self.daemon = True
22 |
23 | def start(self):
24 | if not self.isAlive():
25 | self.stop_event.clear()
26 | threading.Thread.start(self)
27 |
28 | def stop(self):
29 | if self.isAlive():
30 | self.stop_event.set()
31 | self.join()
32 |
33 | class AsyncWorker(StoppableThread):
34 | """Basic thread wrapper class for asynchronously running functions
35 |
36 | Return False from the worker function to abort loop."""
37 | def __init__(self, todo):
38 | StoppableThread.__init__(self)
39 | self.todo = todo
40 |
41 | def run(self):
42 | while not self.stop_event.is_set():
43 | # Explicitly check for False being returned
44 | # from worker, IE: Don't allow None
45 | if self.todo() is False:
46 | self.stop_event.set()
47 | break
48 |
49 | binary=[
50 | 0x0,0xd8,0xb8,0x5,0x6f,0xd5,0x10,0x0,0x3c,0x4,0x9c,0x4,0x1c,0x0,0xa4,0x4,0x7c,0x1,0x2,0x1,0xc,0x0,0x4,0x0,0x7c,0x1,0x10,0x0,0x1,0x37,0x24,0x38,0x1e,0x35,0x3a,0x1,0xc2,0x0,0x6,0x2,0x1,0x3f,0x91,0x35,0xc0,0xec,0x23,0x1,0x38,0xe1,0x6,0x2,0x7,0x35,0x35,0x38,0x1d,0x3e,0xb6,0x35,0x35,0x38,0x1d,0x3e,0xb4,0x0,0x6,0x2,0x4,0x65,0x64,0x34,0xfa,0xa,0x80,0x58,0x64,0x89,0x0,0x88,0x0,0x38,0x5,0xe2,0x89,0x1,0x88,0x0,0x37,0x24,0xe8,0x89,0x2,0x88,0x1,0x37,0x1,0xe8,0x35,0xfa,0xa,0x8,0x1,0x38,0xe1,0x6,0x2,0x7,0x4,0x36,0x88,0x2,0x38,0x1e,0xf9,0xa,0x2a,0x88,0x1,0x36,0xe8,0x88,0x2,0x3d,0xb6,0x88,0x1,0x37,0x0,0xe8,0x36,0xe2,0x88,0x2,0x3d,0xb4,0x1,0x36,0x88,0x2,0x3d,0x96,0x37,0x1,0xe3,0xea,0x88,0x2,0x3d,0x94,0x37,0x21,0xe3,0xea,0x6,0x2,0x7,0x4,0x5,0x1,0x35,0x6,0x2,0x7,0x35,0x37,0x1,0x3e,0x92,0x35,0x37,0x1,0x3e,0x96,0x37,0x24,0xeb,0xe8,0x37,0x4,0xea,0x89,0x9,0x38,0x5,0x38,0x9,0x3e,0x92,0x38,0x5,0x38,0x9,0x3e,0x96,0x37,0x24,0xeb,0xe8,0x37,0x5,0xea,0x89,0xa,0x38,0xa,0x38,0xe,0x3e,0x92,0x38,0xa,0x38,0xe,0x3e,0x96,0x37,0x24,0xeb,0xe8,0x38,0x60,0xea,0x89,0xb,0x37,0x23,0x38,0x13,0x3e,0x92,0x37,0x23,0x38,0x13,0x3e,0x96,0x37,0x24,0xeb,0xe8,0x37,0x6,0xea,0x89,0xc,0x38,0x14,0x38,0x18,0x3e,0x92,0x38,0x14,0x38,0x18,0x3e,0x96,0x37,0x24,0xeb,0xe8,0x38,0xa0,0xea,0x89,0xd,0x38,0x19,0x38,0x1d,0x3e,0x92,0x38,0x19,0x38,0x1d,0x3e,0x96,0x37,0x24,0xeb,0xe8,0x38,0xc0,0xea,0x89,0xe,0x88,0x9,0x88,0x3,0xfb,0xa,0xa,0x1,0x88,0x9,0x6,0x2,0x7,0x88,0x9,0x89,0x3,0x88,0xa,0x88,0x4,0xfb,0xa,0xa,0x1,0x88,0xa,0x6,0x2,0x7,0x88,0xa,0x89,0x4,0x88,0xb,0x88,0x5,0xfb,0xa,0xa,0x1,0x88,0xb,0x6,0x2,0x7,0x88,0xb,0x89,0x5,0x88,0xc,0x88,0x6,0xfb,0xa,0xa,0x1,0x88,0xc,0x6,0x2,0x7,0x88,0xc,0x89,0x6,0x88,0xd,0x88,0x7,0xfb,0xa,0xa,0x1,0x88,0xd,0x6,0x2,0x7,0x88,0xd,0x89,0x7,0x88,0xe,0x88,0x8,0xfb,0xa,0xa,0x1,0x88,0xe,0x6,0x2,0x7,0x88,0xe,0x89,0x8,0x4,0xfe,0xb8,0x32,0x0,0x0,0xb0,0x2,0xc,0x0,0x80,0x1,0x0,0x0,0xa2,0x1,0x0,0x0,0xb0,0x1,0x0,0x0,0xba,0x1,0x0,0x0,0xcd,0x1,0x4,0x0,0xea,0x1,0x0,0x0,0xf6,0x1,0x0,0x0,0x17,0x2,0x0,0x0,0x24,0x2,0x8,0x0,0x70,0x2,0x0,0x0,0x98,0x2,0x0,0x0,0xf0,0xa9,0xbc,0xa0,0x10,0xa8,0xfc,0x80,0x54,0xaa,0xbc,0x8,0x1,0xb2,0xfc,0xa0,0x55,0xb2,0xbc,0x2c,0x4,0xa8,0xfc,0x80,0x54,0xaa,0xbc,0x8,0x1,0xbe,0xfc,0xa0,0x55,0xbe,0xbc,0x2c,0x4,0xa8,0xfc,0x80,0x54,0xae,0xbc,0x8,0x4,0xa8,0xfc,0x80,0x54,0xb0,0xbc,0x8,0x4,0xa8,0xfc,0x80,0x54,0xb4,0xbc,0x8,0x5a,0xc0,0xbc,0xa0,0x10,0xc0,0xfc,0x80,0x4,0xae,0x7c,0x62,0x2,0xae,0x7c,0x61,0x5f,0xe8,0x9b,0x68,0x5f,0xec,0xab,0x68,0x33,0xc8,0xfc,0xa0,0x64,0xbc,0xbc,0x5c,0x1,0xae,0x7c,0x62,0xf2,0xb3,0x3c,0x61,0x16,0x0,0x64,0x5c,0x9,0xb8,0xfc,0xa0,0x58,0xba,0xbc,0xa0,0x1,0xba,0xfc,0x28,0xf1,0xbb,0xbc,0x80,0x58,0xba,0xbc,0x80,0x64,0xbc,0xbc,0x5c,0x5d,0xa8,0xbc,0xa0,0xf1,0xa9,0xbc,0x84,0x0,0xa8,0x7c,0xc1,0x1f,0x0,0x4c,0x5c,0xf2,0xb3,0x3c,0x61,0x1,0xb6,0xfc,0x30,0x1e,0xb8,0xfc,0xe4,0x17,0xb6,0xfc,0x28,0xff,0xb6,0xfc,0x60,0x1,0xae,0x7c,0x62,0xff,0xb6,0xd4,0x6c,0xf0,0xab,0xbc,0x8,0x5a,0xaa,0xbc,0x80,0x55,0xb6,0x3c,0x0,0x5a,0xaa,0xbc,0x84,0x1,0xaa,0xfc,0x80,0xf,0xaa,0xfc,0x60,0xf0,0xab,0x3c,0x8,0x16,0x0,0x7c,0x5c,0x5e,0xc8,0xbc,0x5c,0xf0,0xa9,0xbc,0xa0,0x8,0xa8,0xfc,0x80,0x54,0xaa,0xbc,0x8,0x4,0xa8,0xfc,0x80,0x54,0xac,0xbc,0x8,0x56,0xaa,0x3c,0x86,0x33,0x0,0x68,0x5c,0x60,0xac,0xbc,0x80,0x56,0xc2,0xbc,0x0,0x60,0xac,0xbc,0x84,0x1,0xac,0xfc,0x80,0xf,0xac,0xfc,0x60,0x54,0xac,0x3c,0x8,0x0,0xc3,0xfc,0x68,0x2,0xc2,0xfc,0x2c,0x1,0xc2,0xfc,0x68,0xb,0xc4,0xfc,0xa0,0xf1,0xc7,0xbc,0xa0,0x4,0xae,0x7c,0x62,0x2,0xae,0x7c,0x61,0x1,0xc2,0xe0,0x6c,0x1,0xc2,0xfc,0x29,0x5f,0xe8,0xab,0x70,0x5f,0xec,0x97,0x74,0x58,0xc6,0xbc,0x80,0x5e,0xc8,0xbc,0x5c,0x63,0xa8,0xbc,0xa0,0xf1,0xa9,0xbc,0x84,0x0,0xa8,0x7c,0xc1,0x4d,0x0,0x4c,0x5c,0x46,0xc4,0xfc,0xe4,0x33,0x0,0x7c,0x5c,0x1,0x5,0x2,0x47,0x35,0x37,0x1,0x1a,0x57,0x67,0x37,0x21,0x1e,0x35,0xc0,0x70,0xf6,0xc9,0x20,0x8b,0x28,0xc9,0x24,0x34,0xc7,0x30,0x47,0x28,0x36,0xec,0x42,0x80,0x61,0x32,0x40,0xa,0x5,0x42,0x98,0x36,0xed,0x21,0x47,0x35,0x38,0x9,0x1a,0x32,0x0,0x5,0x4,0x35,0xfe,0xa,0x2,0x4,0x77,0x32,0x62,0x3e,0x48,0x44,0xfb,0xa,0xb,0x48,0x98,0x28,0x61,0x48,0x36,0xec,0x37,0x23,0xe8,0x49,0x32,0x3f,0x91,0x69,0x0,0x5,0x4,0x62,0x80,0x35,0xfe,0x3f,0x91,0x68,0xed,0x35,0xc0,0x39,0x3,0xe8,0xf6,0xf6,0x64,0xfa,0xf2,0xb,0x2,0x4,0x67,0x32,0x0,0x5,0x4,0x62,0x80,0x35,0xf9,0xa,0x2,0x4,0x75,0x32,0x50,0x4c,0x36,0xec,0x37,0x23,0xe8,0xfb,0xb,0x2,0x4,0x74,0x64,0x4c,0x99,0x38,0x4c,0x36,0xec,0x37,0x23,0xe8,0x4d,0x5c,0x37,0x2,0xe8,0xa,0x3,0x1,0x5,0x6,0x32,0x64,0x16,0x8,0x8,0x1,0x66,0xae,0x80,0x5,0x7,0x9,0x78,0x32,0x64,0x37,0x1e,0xfc,0x6d,0x64,0x35,0xf9,0xa,0xa,0x64,0x6c,0xec,0xe9,0x65,0x1,0x38,0x2d,0x5,0x7,0x3b,0x3b,0x9a,0xca,0x0,0x69,0x38,0xa,0x8,0x2d,0x64,0x68,0xfe,0xa,0x16,0x1,0x64,0x68,0xf6,0x38,0x30,0xec,0x6c,0x68,0x36,0xfc,0xf4,0xec,0x5,0x7,0x68,0x66,0x57,0x62,0x1c,0x4,0xc,0x60,0x68,0x36,0xfc,0xf2,0xa,0x5,0x1,0x38,0x30,0x5,0x7,0x38,0xa,0x6a,0x56,0x9,0x53,0x32,0x37,0x2,0x68,0xed,0x37,0x0,0xe3,0x66,0x43,0x68,0x8,0x1b,0x1,0x35,0x39,0x2,0x93,0x37,0x1,0x66,0xc1,0x37,0x23,0xe8,0x38,0x30,0x38,0x39,0x12,0x38,0x41,0x38,0x46,0x12,0xf,0x5,0x7,0x9,0x65,0x32,0x37,0x4,0x68,0xed,0x66,0x43,0x68,0x8,0xd,0x1,0x36,0x66,0xc1,0x36,0xe8,0x38,0x30,0xec,0x5,0x7,0x9,0x73,0x32,0x0
51 | ]
52 |
53 | print('Setting up Propeller HAT')
54 | l = p1.loader.Loader('/dev/ttyAMA0',17)
55 | l.upload(code=''.join(map(chr,binary)),progress=p1.loader.print_status)
56 |
57 | dev = serial.Serial('/dev/ttyAMA0',baudrate=115200, timeout=0)
58 |
59 | _CMD_MODE = 0
60 | _CMD_WRITE = 1
61 |
62 | OUTPUT = 1
63 | INPUT = 0
64 | HIGH = 1
65 | LOW = 0
66 |
67 | ina = [0]*30
68 |
69 | fw_version = None
70 |
71 | def _poll():
72 | result = dev.read()
73 | if result != '':
74 | result = ord(result)
75 | #print bin(result).replace('0b','').rjust(8, '0')
76 |
77 | cmd = result >> 5
78 | data = result & 0b00011111
79 | if cmd == 0: # CMD status message
80 | if data & 1: # Pin Okay
81 | direction = (data & 0b0010000) > 0
82 | value = (data & 0b00001000) > 0
83 | #print("OK: Dir: {} Value: {}".format(direction, value))
84 | return True
85 | else: # Range Err
86 | #print("ERR: Pin out of range!")
87 | return False
88 | elif cmd == 7:
89 | #print("Got FW version {}".format(data))
90 | fw_version = data
91 | else: # CMD pin update
92 | offset = (cmd-1)*5
93 | ina[offset:offset+5] = (int(x) for x in list(bin(data).replace('0b','').rjust(5,'0')))
94 | #print(ina)
95 |
96 | return True
97 |
98 | def mode(pin, value):
99 | cmd = pin
100 | cmd = cmd | (_CMD_MODE << 6)
101 | cmd = cmd | (value << 5)
102 | dev.write(chr(cmd))
103 |
104 | def write(pin, value):
105 | cmd = pin
106 | cmd = cmd | (_CMD_WRITE << 6)
107 | cmd = cmd | (value << 5)
108 | dev.write(chr(cmd))
109 |
110 | def read(pin):
111 | return ina[pin]
112 |
113 | t = AsyncWorker(_poll)
114 | t.start()
115 |
116 | atexit.register(lambda: t.stop())
117 |
--------------------------------------------------------------------------------
/software/python/library/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """
4 | Copyright (c) 2014 Pimoroni
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of
7 | this software and associated documentation files (the "Software"), to deal in
8 | the Software without restriction, including without limitation the rights to
9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10 | of the Software, and to permit persons to whom the Software is furnished to do
11 | so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 | """
24 |
25 | try:
26 | from setuptools import setup
27 | except ImportError:
28 | from distutils.core import setup
29 |
30 | classifiers = ['Development Status :: 5 - Production/Stable',
31 | 'Operating System :: POSIX :: Linux',
32 | 'License :: OSI Approved :: MIT License',
33 | 'Intended Audience :: Developers',
34 | 'Programming Language :: Python :: 2.6',
35 | 'Programming Language :: Python :: 2.7',
36 | 'Programming Language :: Python :: 3',
37 | 'Topic :: Software Development',
38 | 'Topic :: System :: Hardware']
39 |
40 | setup(
41 | name = 'p1',
42 | version = '1.0.1',
43 | author = 'Philip Howard',
44 | author_email = 'phil@pimoroni.com',
45 | description = 'Parallax Propeller software uploader.',
46 | long_description= open('README.txt').read() + open('CHANGELOG.txt').read(),
47 | license = 'MIT',
48 | keywords = 'Parallax Propeller',
49 | url = 'http://www.pimoroni.com',
50 | classifiers = classifiers,
51 | packages = ['p1'],
52 | install_requires= ['RPi.GPIO >= 0.5.5','pyserial >= 2.6']
53 | )
54 |
--------------------------------------------------------------------------------
/software/python/library/src/.gitignore:
--------------------------------------------------------------------------------
1 | *.binary
2 |
--------------------------------------------------------------------------------
/software/python/library/src/io/I2C slave v1.2.spin:
--------------------------------------------------------------------------------
1 | {{┌──────────────────────────────────────────┐
2 | │ I2C slave object │
3 | │ Author: Chris Gadd │
4 | │ Copyright (c) 2013 Chris Gadd │
5 | │ See end of file for terms of use. │
6 | └──────────────────────────────────────────┘
7 |
8 | This object creates an I2C slave device with 32 byte-sized registers on the Propeller, which an I2C master device can read from and write to using standard protocol:
9 | 7-bit device ID + read/write bit, 8-bit register address, 8 bits of data
10 | Supports single, repeated, and page reads and writes
11 | Does NOT check for overruns - Writing a page of bytes starting at register 31 may produce unexpected results
12 |
13 | To use:
14 | slave.start(28,29,$42) Start the slave object using p28 for clock, p29 for data, with device ID $42
15 | slave.check Returns the index (31-0) of the highest byte in the register that was written to by a master
16 | Subsequent calls to slave.check return the index of the next highest byte with new data
17 | slave.check_reg(5) Returns the contents of register 5 only if the new-data flag for that register is set, returns -1 otherwise
18 | slave.check_flags Returns all 32 flags as a long
19 | slave.check_flag(1) Returns true if flags bit 1 is set
20 | slave.clear_flag(1) Clears flags bit 1
21 | slave.get(10) Returns the value of register 10
22 | slave.put(11,#2) Stores the value 2 in register 11
23 | slave.flush Clears all 32 registers to 0
24 | slave.address Returns the base address of the slave registers - useful for directly operating on the registers
25 | by higher-level objects
26 |
27 | Tested up to 769Kbps (max transmit speed of the master object)
28 |
29 | }}
30 | VAR
31 | long flags ' Used to determine if a register has new data from the master
32 |
33 | byte _slave_address
34 | byte SCL_pin
35 | byte SDA_pin
36 |
37 | byte register[256]
38 |
39 | byte cog
40 |
41 | PUB start(clk_pin, data_pin, slave_address) : okay
42 | stop
43 | _slave_address := slave_address
44 | SCL_pin := clk_pin
45 | SDA_pin := data_pin
46 |
47 | okay := cog := cognew(@entry, @flags) + 1
48 |
49 | PUB stop
50 | if cog
51 | cogstop(cog~ - 1)
52 |
53 | PUB address
54 | return @register
55 |
56 | PUB check : index
57 | {{
58 | Returns the number of the highest byte that was written to:
59 | If an I2C master wrote to addresses 3 and 7 of the slave's buffer, #7 is returned
60 | The flag for the highest byte is then cleared, so a subsequent check would return #3
61 | Returns -1 if all updated byte addresses have been returned (no new data)
62 | }}
63 | index := (>| flags) - 1
64 | flags := flags & !(|< index) ' Clear the highest set bit
65 |
66 | PUB check_reg(index)
67 | {{
68 | Returns the value of the indexed register if that register has new data
69 | Returns -1 otherwise
70 | }}
71 |
72 | if |< index & flags
73 | flags := flags & !(|< index)
74 | return register[index]
75 | return -1
76 |
77 | PUB check_flags
78 | return flags
79 |
80 | PUB check_flag(index)
81 | return |< index & flags
82 |
83 | PUB clear_flag(index)
84 | flags := flags & !(|< index)
85 |
86 | PUB get(index)
87 | return register[index]
88 |
89 | PUB put(index,data)
90 | register[index] := data
91 |
92 | PUB flush | i
93 | flags~
94 | bytefill(@register,0,256)
95 |
96 | DAT org
97 | entry
98 | mov t1,par
99 | mov flags_address,t1 ' Retrieve all of the addresses and
100 | add t1,#4 ' pin assignments from the VAR block,
101 | rdbyte device_address,t1 ' and create bit masks
102 | shl device_address,#1
103 | add t1,#1
104 | rdbyte t2,t1
105 | mov SCL_mask,#1
106 | shl SCL_mask,t2
107 | add t1,#1
108 | rdbyte t2,t1
109 | mov SDA_mask,#1
110 | shl SDA_mask,t2
111 | add t1,#1
112 | mov register_address,t1
113 | mov idle_mask,SCL_mask
114 | or idle_mask,SDA_mask
115 | '----------------------------------------------------------------------------------------------------------------------
116 | wait_for_start ' SCL
117 | waitpeq idle_mask,idle_mask ' SDA
118 | :loop
119 | waitpne SDA_mask,SDA_mask
120 | test SCL_mask,ina wc
121 | if_nc jmp #wait_for_start
122 | start_detected
123 | call #receive
124 | mov t1,I2C_byte
125 | and t1,#%1111_1110 ' clear the read/write flag and compare received
126 | cmp t1,device_address wz ' device address with assigned address
127 | if_ne jmp #wait_for_start
128 | call #ack
129 | test I2C_byte,#%0000_0001 wc ' test read(1) or write(0) bit of device address
130 | if_nc jmp #write
131 | read '(from_master)
132 | call #respond ' The master sends an ACK or NAK in response to
133 | add data_address,#1 ' every byte sent back from the slave
134 | if_nc jmp #read ' Send another byte if ACK (c=0)
135 | jmp #wait_for_start ' Stop if NAK (c=1)
136 | write '(from_master)
137 | rdlong t1,flags_address ' Use t1 to hold all flags
138 | mov t2,#1 ' Use t2 to hold the flag of the current register
139 | mov data_address,register_address ' Prepare the to store new data
140 | call #receive ' First byte received is a register address
141 | add data_address,I2C_byte
142 | shl t2,I2C_byte ' Shift the flag to the appropriate register
143 | call #ack
144 | or t1,t2 ' Update the flag here in case master only sends
145 | ' ID and register (I2C.command)
146 | :loop
147 | call #receive ' Receive a data byte
148 | wrbyte I2C_byte,data_address ' Store in the addressed register
149 | add data_address,#1 ' Address the next register
150 | or t1,t2 ' Update the flags
151 | wrlong t1,flags_address
152 | shl t2,#1 ' Shift the flag to the next register
153 | call #ack
154 | jmp #:loop
155 | '======================================================================================================================
156 | receive ' (Read)
157 | mov loop_counter,#7 '
158 | mov I2C_byte,#0 ' SCL
159 | waitpne SCL_mask,SCL_mask ' SDA ───────
160 | waitpeq SCL_mask,SCL_mask
161 | test SDA_mask,ina wc
162 | rcl I2C_byte,#1
163 | if_c jmp #:detect_restart ' The first bit of a received byte may be b7,
164 | :detect_stop ' SCL ' a stop, or a restart.
165 | test SCL_mask,ina wz ' SDA ' Not a stop or restart if
166 | if_z jmp #:loop ' clock goes low without
167 | test SDA_mask,ina wz ' data changing state
168 | ' if_nz jmp #wait_for_start '
169 | if_nz jmp #stopping
170 | jmp #:detect_stop
171 | :detect_restart ' SCL
172 | test SCL_mask,ina wz ' SDA
173 | if_z jmp #:loop
174 | test SDA_mask,ina wz
175 | if_z jmp #start_detected
176 | jmp #:detect_restart
177 | :loop
178 | waitpne SCL_mask,SCL_mask
179 | waitpeq SCL_mask,SCL_mask
180 | test SDA_mask,ina wc
181 | rcl I2C_byte,#1
182 | djnz loop_counter,#:loop
183 | receive_ret ret
184 | '....................
185 | stopping ' This is where flags would be updated in case
186 | wrlong t1,flags_address ' master only sends ID and register (I2C.command)
187 | jmp #wait_for_start ' doesn't have any affect when writing or reading
188 | '----------------------------------------------------------------------------------------------------------------------
189 | respond ' (Write) (Read ACK or NAK)
190 | mov loop_counter,#8 '
191 | rdbyte I2C_byte,data_address ' SCL
192 | shl I2C_byte,#32-8 ' SDA ───────
193 | :loop
194 | waitpne SCL_mask,SCL_mask
195 | shl I2C_byte,#1 wc
196 | muxnc dira,SDA_mask
197 | waitpeq SCL_mask,SCL_mask
198 | waitpne SCL_mask,SCL_mask
199 | djnz loop_counter,#:loop
200 | andn dira,SDA_mask
201 | 'receive_ack_or_nak
202 | waitpne SCL_mask,SCL_mask
203 | waitpeq SCL_mask,SCL_mask
204 | test SDA_mask,ina wc ' C is set if NAK
205 | waitpne SCL_mask,SCL_mask
206 | respond_ret ret
207 | '----------------------------------------------------------------------------------------------------------------------
208 | ack ' SCL
209 | waitpne SCL_mask,SCL_mask ' SDA
210 | or dira,SDA_mask
211 | waitpeq SCL_mask,SCL_mask
212 | waitpne SCL_mask,SCL_mask
213 | andn dira,SDA_mask
214 | ack_ret ret
215 | '----------------------------------------------------------------------------------------------------------------------
216 | 'nak ' SCL
217 | ' waitpne SCL_mask,SCL_mask ' SDA
218 | ' waitpeq SCL_mask,SCL_mask
219 | ' waitpne SCL_mask,SCL_mask ' Might want to send a NAK if the master tries addressing an out-of-range register
220 | 'nak_ret ret
221 | '----------------------------------------------------------------------------------------------------------------------
222 | SCL_mask res 1
223 | SDA_mask res 1
224 | idle_mask res 1
225 |
226 | device_address res 1
227 | register_address res 1
228 | data_address res 1
229 | flags_address res 1
230 |
231 | I2C_byte res 1
232 | loop_counter res 1
233 | t1 res 1
234 | t2 res 1
235 |
236 | fit
237 |
238 | DAT
239 | {{
240 | ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
241 | │ TERMS OF USE: MIT License │
242 | ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
243 | │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
244 | │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
245 | │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
246 | │is furnished to do so, subject to the following conditions: │
247 | │ │
248 | │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
249 | │ │
250 | │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
251 | │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
252 | │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
253 | │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
254 | └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
255 | }}
--------------------------------------------------------------------------------
/software/python/library/src/io/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | openspin -b -o io.binary io.spin
3 |
4 | clean:
5 | rm *.binary
6 |
--------------------------------------------------------------------------------
/software/python/library/src/io/io.spin:
--------------------------------------------------------------------------------
1 | CON
2 | _clkmode = xtal1 + pll16x
3 | _xinfreq = 6_000_000
4 |
5 | SDA_pin = 27
6 | SCL_pin = 26
7 |
8 | VAR
9 | long reg
10 |
11 | OBJ
12 | slave : "I2C slave v1.2"
13 |
14 | PUB Main | i
15 | slave.start(SCL_pin,SDA_pin,$17) ' Start the slave object with a device address of $42
16 |
17 | ' Default all pins as inputs
18 | repeat i from 0 to 31
19 | dira[i] := 0
20 | outa[i] := 0
21 |
22 | ' Continuously poll the registers for changes
23 | ' and update output pins accordingly
24 | repeat
25 | repeat i from 0 to 27
26 |
27 | ' High 32 registers for direction
28 | 'reg := slave.check_reg(i+32)
29 | 'if reg > -1
30 | dira[i] := slave.get(i+32) == 1
31 |
32 | ' Low 32 registers for state
33 | outa[i] := slave.get(i) == 1
34 |
35 | slave.put(i+64,ina[i])
--------------------------------------------------------------------------------
/software/python/library/src/pwm/FullDuplexSerial.spin:
--------------------------------------------------------------------------------
1 | {{
2 | Object file: FullDuplexSerial.spin
3 | Version: 1.2.1
4 | Date: 2006 - 2011
5 | Author: Chip Gracey, Jeff Martin, Daniel Harris
6 | Company: Parallax Semiconductor
7 | Email: dharris@parallaxsemiconductor.com
8 | Licensing: MIT License - see end of file for terms of use.
9 |
10 | Description:
11 | This driver, once started, implements a serial port in one cog.
12 |
13 | Revision History:
14 | v1.2.1 - 5/1/2011 Added extra comments and demonstration code to bring up
15 | to gold standard.
16 | v1.2 - 5/7/2009 Fixed bug in dec method causing largest negative value
17 | (-2,147,483,648) to be output as -0.
18 | v1.1 - 3/1/2006 First official release.
19 |
20 |
21 | =============================================
22 | Connection Diagram
23 | =============================================
24 |
25 | ┌─────────┐
26 | │ │
27 | │ rxPin├─── TTL level RX line
28 | │ txPin├─── TTL level TX line
29 | │ │
30 | └─────────┘
31 | Propeller
32 | MCU
33 | (P8X32A)
34 |
35 | Components:
36 | N/A
37 |
38 | =============================================
39 | }}
40 |
41 |
42 | VAR
43 |
44 | 'Global variable declarations
45 |
46 | long cog 'cog flag/id
47 |
48 | '9 longs, MUST be contiguous
49 | long rx_head
50 | long rx_tail
51 | long tx_head
52 | long tx_tail
53 | long rx_pin
54 | long tx_pin
55 | long rxtx_mode
56 | long bit_ticks
57 | long buffer_ptr
58 |
59 | byte rx_buffer[16] 'transmit and receive buffers
60 | byte tx_buffer[16] '16 bytes each
61 |
62 |
63 | PUB Start(rxPin, txPin, mode, baudrate) : okay
64 | {{
65 | Start serial driver - starts a cog
66 |
67 |
68 | Parameters: rxPin = Propeller pin to set up as RX-ing pin. Range = 0 - 31
69 | txPin = Propeller pin to set up as TX-ing pin. Range = 0 - 31
70 | mode = bitwise mode configuration variable, see mode bit description below.
71 | baudrate = baud rate to transmit bits at.
72 |
73 | mode bit 0 = invert rx
74 | mode bit 1 = invert tx
75 | mode bit 2 = open-drain/source tx
76 | mode bit 3 = ignore tx echo on rx
77 |
78 | return: Numeric value of the cog(1-8) that was started, false(0) if no cog is available.
79 |
80 | example usage: serial.start(31, 30, %0000, 9_600)
81 |
82 | expected outcome of example usage call: Starts a serial port on Propller pins 30 and 31.
83 | The serial port does not invert the RX and TX data,
84 | no open-drain/source on the TX pin, does not ignore
85 | data echoed on RX pin, at 9,600 baud.
86 | }}
87 |
88 | Stop 'make sure the driver isnt already running
89 | longfill(@rx_head, 0, 4) 'zero out the buffer pointers
90 | longmove(@rx_pin, @rxpin, 3) 'copy the start parameters to this objects pin variables
91 | bit_ticks := clkfreq / baudrate 'number of clock ticks per bit for the desired baudrate
92 | buffer_ptr := @rx_buffer 'save the address of the receive buffer
93 | okay := cog := cognew(@entry, @rx_head) + 1 'start the new cog now, assembly cog at "entry" label.
94 |
95 |
96 | PUB Stop
97 | {{
98 | Stop serial driver if it has already been started - frees the cog
99 |
100 | Parameters: none
101 | return: none
102 |
103 | example usage: serial.stop
104 |
105 | expected outcome of example usage call: Stops an already started serial port.
106 | }}
107 |
108 | if cog
109 | cogstop(cog~ - 1) 'if the driver is already running, stop the cog
110 | longfill(@rx_head, 0, 9) 'zero out configuration variables
111 |
112 |
113 | PUB RxFlush
114 | {{
115 | Continuously pops the head of the receive buffer until no bytes remain.
116 |
117 | Parameters: none
118 | return: none
119 |
120 | example usage: serial.RxFlush
121 |
122 | expected outcome of example usage call: Receive bffer will be cleared.
123 | }}
124 |
125 | repeat while RxCheck => 0 'Call RxCheck until buffer is empty
126 |
127 |
128 | PUB RxCheck : rxByte
129 | {{
130 | Check if a byte is waiting in the receive buffer and return the byte if one is there,
131 | does NOT block (never waits).
132 |
133 | Parameters: none
134 | return: If no byte, then return(-1). If byte, then return(byte).
135 |
136 | example usage: serial.RxCheck
137 |
138 | expected outcome of example usage call: Return a byte if one is available, but dont wait
139 | for a byte to come in.
140 | }}
141 |
142 |
143 | rxByte-- 'make rxbyte = -1
144 | if rx_tail <> rx_head 'if a byte is in the buffer, then
145 | rxByte := rx_buffer[rx_tail] ' grab it and store in rxByte
146 | rx_tail := (rx_tail + 1) & $F ' advance the buffer pointer
147 |
148 |
149 | PUB RxTime(ms) : rxByte | t
150 | {{
151 | Wait ms milliseconds for a byte to be received
152 |
153 | Parameters: ms = number of milliseconds to wait for a byte to be received.
154 | return: If no byte, then return(-1). If byte, then return(byte).
155 |
156 | example usage: serial.RxTime(500)
157 |
158 | expected outcome of example usage call: Wait half a second (500 ms) for a byte to be received.
159 | }}
160 |
161 | t := cnt 'take note of the current time
162 | repeat until (rxByte := RxCheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms
163 |
164 |
165 | PUB Rx : rxByte
166 | {{
167 | Receive byte (may wait for byte)
168 | returns $00..$FF
169 |
170 | Parameters: none
171 | return: received byte
172 |
173 | example usage: serial.Rx
174 |
175 | expected outcome of example usage call: Wait until a byte has been received, then return that byte.
176 | }}
177 |
178 | repeat while (rxByte := RxCheck) < 0 'return the byte, wait while the buffer is empty
179 |
180 |
181 | PUB Tx(txByte)
182 | {{
183 | Places a byte into the transmit buffer for transmission (may wait for room in buffer).
184 |
185 | Parameters: txByte = the byte to be transmitted
186 | return: none
187 |
188 | example usage: serial.Tx($0D)
189 |
190 | expected outcome of example usage call: Transmits the byte $0D serially on the txPin
191 | }}
192 |
193 | repeat until (tx_tail <> (tx_head + 1) & $F) 'wait until the buffer has room
194 | tx_buffer[tx_head] := txByte 'place the byte into the buffer
195 | tx_head := (tx_head + 1) & $F 'advance the buffer's pointer
196 |
197 | if rxtx_mode & %1000 'if ignoring rx echo
198 | Rx ' receive the echoed byte and discard
199 |
200 |
201 | PUB Str(stringPtr)
202 | {{
203 | Transmit a string of bytes
204 |
205 | Parameters: stringPtr = the pointer address of the null-terminated string to be sent
206 | return: none
207 |
208 | example usage: serial.Str(@test_string)
209 |
210 | expected outcome of example usage call: Transmits each byte of a string at the address some_string.
211 | }}
212 |
213 | repeat strsize(stringPtr)
214 | Tx(byte[stringPtr++]) 'Transmit each byte in the string
215 |
216 |
217 | PUB Dec(value) | i, x
218 | {{
219 | Transmit the ASCII string equivalent of a decimal value
220 |
221 | Parameters: dec = the numeric value to be transmitted
222 | return: none
223 |
224 | example usage: serial.Dec(-1_234_567_890)
225 |
226 | expected outcome of example usage call: Will print the string "-1234567890" to a listening terminal.
227 | }}
228 |
229 | x := value == NEGX 'Check for max negative
230 | if value < 0
231 | value := ||(value+x) 'If negative, make positive; adjust for max negative
232 | Tx("-") 'and output sign
233 |
234 | i := 1_000_000_000 'Initialize divisor
235 |
236 | repeat 10 'Loop for 10 digits
237 | if value => i
238 | Tx(value / i + "0" + x*(i == 1)) 'If non-zero digit, output digit; adjust for max negative
239 | value //= i 'and digit from value
240 | result~~ 'flag non-zero found
241 | elseif result or i == 1
242 | Tx("0") 'If zero digit (or only digit) output it
243 | i /= 10 'Update divisor
244 |
245 |
246 | PUB Hex(value, digits)
247 | {{
248 | Transmit the ASCII string equivalent of a hexadecimal number
249 |
250 | Parameters: value = the numeric hex value to be transmitted
251 | digits = the number of hex digits to print
252 | return: none
253 |
254 | example usage: serial.Hex($AA_FF_43_21, 8)
255 |
256 | expected outcome of example usage call: Will print the string "AAFF4321" to a listening terminal.
257 | }}
258 |
259 | value <<= (8 - digits) << 2
260 | repeat digits 'do it for the number of hex digits being transmitted
261 | Tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))' Transmit the ASCII value of the hex characters
262 |
263 |
264 | PUB Bin(value, digits)
265 | {{
266 | Transmit the ASCII string equivalent of a binary number
267 |
268 | Parameters: value = the numeric binary value to be transmitted
269 | digits = the number of binary digits to print
270 | return: none
271 |
272 | example usage: serial.Bin(%1110_0011_0000_1100_1111_1010_0101_1111, 32)
273 |
274 | expected outcome of example usage call: Will print the string "11100011000011001111101001011111" to a listening terminal.
275 | }}
276 |
277 | value <<= 32 - digits
278 | repeat digits
279 | Tx((value <-= 1) & 1 + "0") 'Transmit the ASCII value of each binary digit
280 |
281 |
282 | DAT
283 |
284 | '***********************************
285 | '* Assembly language serial driver *
286 | '***********************************
287 |
288 | org
289 | '
290 | '
291 | ' Entry
292 | '
293 | entry mov t1,par 'get structure address
294 | add t1,#4 << 2 'skip past heads and tails
295 |
296 | rdlong t2,t1 'get rx_pin
297 | mov rxmask,#1
298 | shl rxmask,t2
299 |
300 | add t1,#4 'get tx_pin
301 | rdlong t2,t1
302 | mov txmask,#1
303 | shl txmask,t2
304 |
305 | add t1,#4 'get rxtx_mode
306 | rdlong rxtxmode,t1
307 |
308 | add t1,#4 'get bit_ticks
309 | rdlong bitticks,t1
310 |
311 | add t1,#4 'get buffer_ptr
312 | rdlong rxbuff,t1
313 | mov txbuff,rxbuff
314 | add txbuff,#16
315 |
316 | test rxtxmode,#%100 wz 'init tx pin according to mode
317 | test rxtxmode,#%010 wc
318 | if_z_ne_c or outa,txmask
319 | if_z or dira,txmask
320 |
321 | mov txcode,#transmit 'initialize ping-pong multitasking
322 | '
323 | '
324 | ' Receive
325 | '
326 | receive jmpret rxcode,txcode 'run a chunk of transmit code, then return
327 |
328 | test rxtxmode,#%001 wz 'wait for start bit on rx pin
329 | test rxmask,ina wc
330 | if_z_eq_c jmp #receive
331 |
332 | mov rxbits,#9 'ready to receive byte
333 | mov rxcnt,bitticks
334 | shr rxcnt,#1
335 | add rxcnt,cnt
336 |
337 | :bit add rxcnt,bitticks 'ready next bit period
338 |
339 | :wait jmpret rxcode,txcode 'run a chuck of transmit code, then return
340 |
341 | mov t1,rxcnt 'check if bit receive period done
342 | sub t1,cnt
343 | cmps t1,#0 wc
344 | if_nc jmp #:wait
345 |
346 | test rxmask,ina wc 'receive bit on rx pin
347 | rcr rxdata,#1
348 | djnz rxbits,#:bit
349 |
350 | shr rxdata,#32-9 'justify and trim received byte
351 | and rxdata,#$FF
352 | test rxtxmode,#%001 wz 'if rx inverted, invert byte
353 | if_nz xor rxdata,#$FF
354 |
355 | rdlong t2,par 'save received byte and inc head
356 | add t2,rxbuff
357 | wrbyte rxdata,t2
358 | sub t2,rxbuff
359 | add t2,#1
360 | and t2,#$0F
361 | wrlong t2,par
362 |
363 | jmp #receive 'byte done, receive next byte
364 | '
365 | '
366 | ' Transmit
367 | '
368 | transmit jmpret txcode,rxcode 'run a chunk of receive code, then return
369 |
370 | mov t1,par 'check for head <> tail
371 | add t1,#2 << 2
372 | rdlong t2,t1
373 | add t1,#1 << 2
374 | rdlong t3,t1
375 | cmp t2,t3 wz
376 | if_z jmp #transmit
377 |
378 | add t3,txbuff 'get byte and inc tail
379 | rdbyte txdata,t3
380 | sub t3,txbuff
381 | add t3,#1
382 | and t3,#$0F
383 | wrlong t3,t1
384 |
385 | or txdata,#$100 'ready byte to transmit
386 | shl txdata,#2
387 | or txdata,#1
388 | mov txbits,#11
389 | mov txcnt,cnt
390 |
391 | :bit test rxtxmode,#%100 wz 'output bit on tx pin according to mode
392 | test rxtxmode,#%010 wc
393 | if_z_and_c xor txdata,#1
394 | shr txdata,#1 wc
395 | if_z muxc outa,txmask
396 | if_nz muxnc dira,txmask
397 | add txcnt,bitticks 'ready next cnt
398 |
399 | :wait jmpret txcode,rxcode 'run a chunk of receive code, then return
400 |
401 | mov t1,txcnt 'check if bit transmit period done
402 | sub t1,cnt
403 | cmps t1,#0 wc
404 | if_nc jmp #:wait
405 |
406 | djnz txbits,#:bit 'another bit to transmit?
407 |
408 | jmp #transmit 'byte done, transmit next byte
409 | '
410 | '
411 | ' Uninitialized data
412 | '
413 | t1 res 1
414 | t2 res 1
415 | t3 res 1
416 |
417 | rxtxmode res 1
418 | bitticks res 1
419 |
420 | rxmask res 1
421 | rxbuff res 1
422 | rxdata res 1
423 | rxbits res 1
424 | rxcnt res 1
425 | rxcode res 1
426 |
427 | txmask res 1
428 | txbuff res 1
429 | txdata res 1
430 | txbits res 1
431 | txcnt res 1
432 | txcode res 1
433 |
434 |
435 | DAT
436 | {{
437 | ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
438 | │ TERMS OF USE: MIT License │
439 | ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
440 | │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
441 | │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
442 | │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
443 | │is furnished to do so, subject to the following conditions: │
444 | │ │
445 | │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
446 | │ │
447 | │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
448 | │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
449 | │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
450 | │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
451 | └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
452 | }}
--------------------------------------------------------------------------------
/software/python/library/src/pwm/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | openspin -b -o io-pwm.binary io-pwm.spin
3 |
4 | clean:
5 | rm *.binary
6 |
--------------------------------------------------------------------------------
/software/python/library/src/pwm/PWM_32_v4.spin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/software/python/library/src/pwm/PWM_32_v4.spin
--------------------------------------------------------------------------------
/software/python/library/src/pwm/io-pwm.spin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/software/python/library/src/pwm/io-pwm.spin
--------------------------------------------------------------------------------
/software/python/library/src/serialio/FullDuplexSerial.spin:
--------------------------------------------------------------------------------
1 | {{
2 | Object file: FullDuplexSerial.spin
3 | Version: 1.2.1
4 | Date: 2006 - 2011
5 | Author: Chip Gracey, Jeff Martin, Daniel Harris
6 | Company: Parallax Semiconductor
7 | Email: dharris@parallaxsemiconductor.com
8 | Licensing: MIT License - see end of file for terms of use.
9 |
10 | Description:
11 | This driver, once started, implements a serial port in one cog.
12 |
13 | Revision History:
14 | v1.2.1 - 5/1/2011 Added extra comments and demonstration code to bring up
15 | to gold standard.
16 | v1.2 - 5/7/2009 Fixed bug in dec method causing largest negative value
17 | (-2,147,483,648) to be output as -0.
18 | v1.1 - 3/1/2006 First official release.
19 |
20 |
21 | =============================================
22 | Connection Diagram
23 | =============================================
24 |
25 | ┌─────────┐
26 | │ │
27 | │ rxPin├─── TTL level RX line
28 | │ txPin├─── TTL level TX line
29 | │ │
30 | └─────────┘
31 | Propeller
32 | MCU
33 | (P8X32A)
34 |
35 | Components:
36 | N/A
37 |
38 | =============================================
39 | }}
40 |
41 |
42 | VAR
43 |
44 | 'Global variable declarations
45 |
46 | long cog 'cog flag/id
47 |
48 | '9 longs, MUST be contiguous
49 | long rx_head
50 | long rx_tail
51 | long tx_head
52 | long tx_tail
53 | long rx_pin
54 | long tx_pin
55 | long rxtx_mode
56 | long bit_ticks
57 | long buffer_ptr
58 |
59 | byte rx_buffer[16] 'transmit and receive buffers
60 | byte tx_buffer[16] '16 bytes each
61 |
62 |
63 | PUB Start(rxPin, txPin, mode, baudrate) : okay
64 | {{
65 | Start serial driver - starts a cog
66 |
67 |
68 | Parameters: rxPin = Propeller pin to set up as RX-ing pin. Range = 0 - 31
69 | txPin = Propeller pin to set up as TX-ing pin. Range = 0 - 31
70 | mode = bitwise mode configuration variable, see mode bit description below.
71 | baudrate = baud rate to transmit bits at.
72 |
73 | mode bit 0 = invert rx
74 | mode bit 1 = invert tx
75 | mode bit 2 = open-drain/source tx
76 | mode bit 3 = ignore tx echo on rx
77 |
78 | return: Numeric value of the cog(1-8) that was started, false(0) if no cog is available.
79 |
80 | example usage: serial.start(31, 30, %0000, 9_600)
81 |
82 | expected outcome of example usage call: Starts a serial port on Propller pins 30 and 31.
83 | The serial port does not invert the RX and TX data,
84 | no open-drain/source on the TX pin, does not ignore
85 | data echoed on RX pin, at 9,600 baud.
86 | }}
87 |
88 | Stop 'make sure the driver isnt already running
89 | longfill(@rx_head, 0, 4) 'zero out the buffer pointers
90 | longmove(@rx_pin, @rxpin, 3) 'copy the start parameters to this objects pin variables
91 | bit_ticks := clkfreq / baudrate 'number of clock ticks per bit for the desired baudrate
92 | buffer_ptr := @rx_buffer 'save the address of the receive buffer
93 | okay := cog := cognew(@entry, @rx_head) + 1 'start the new cog now, assembly cog at "entry" label.
94 |
95 |
96 | PUB Stop
97 | {{
98 | Stop serial driver if it has already been started - frees the cog
99 |
100 | Parameters: none
101 | return: none
102 |
103 | example usage: serial.stop
104 |
105 | expected outcome of example usage call: Stops an already started serial port.
106 | }}
107 |
108 | if cog
109 | cogstop(cog~ - 1) 'if the driver is already running, stop the cog
110 | longfill(@rx_head, 0, 9) 'zero out configuration variables
111 |
112 |
113 | PUB RxFlush
114 | {{
115 | Continuously pops the head of the receive buffer until no bytes remain.
116 |
117 | Parameters: none
118 | return: none
119 |
120 | example usage: serial.RxFlush
121 |
122 | expected outcome of example usage call: Receive bffer will be cleared.
123 | }}
124 |
125 | repeat while RxCheck => 0 'Call RxCheck until buffer is empty
126 |
127 |
128 | PUB RxCheck : rxByte
129 | {{
130 | Check if a byte is waiting in the receive buffer and return the byte if one is there,
131 | does NOT block (never waits).
132 |
133 | Parameters: none
134 | return: If no byte, then return(-1). If byte, then return(byte).
135 |
136 | example usage: serial.RxCheck
137 |
138 | expected outcome of example usage call: Return a byte if one is available, but dont wait
139 | for a byte to come in.
140 | }}
141 |
142 |
143 | rxByte-- 'make rxbyte = -1
144 | if rx_tail <> rx_head 'if a byte is in the buffer, then
145 | rxByte := rx_buffer[rx_tail] ' grab it and store in rxByte
146 | rx_tail := (rx_tail + 1) & $F ' advance the buffer pointer
147 |
148 |
149 | PUB RxTime(ms) : rxByte | t
150 | {{
151 | Wait ms milliseconds for a byte to be received
152 |
153 | Parameters: ms = number of milliseconds to wait for a byte to be received.
154 | return: If no byte, then return(-1). If byte, then return(byte).
155 |
156 | example usage: serial.RxTime(500)
157 |
158 | expected outcome of example usage call: Wait half a second (500 ms) for a byte to be received.
159 | }}
160 |
161 | t := cnt 'take note of the current time
162 | repeat until (rxByte := RxCheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms
163 |
164 |
165 | PUB Rx : rxByte
166 | {{
167 | Receive byte (may wait for byte)
168 | returns $00..$FF
169 |
170 | Parameters: none
171 | return: received byte
172 |
173 | example usage: serial.Rx
174 |
175 | expected outcome of example usage call: Wait until a byte has been received, then return that byte.
176 | }}
177 |
178 | repeat while (rxByte := RxCheck) < 0 'return the byte, wait while the buffer is empty
179 |
180 |
181 | PUB Tx(txByte)
182 | {{
183 | Places a byte into the transmit buffer for transmission (may wait for room in buffer).
184 |
185 | Parameters: txByte = the byte to be transmitted
186 | return: none
187 |
188 | example usage: serial.Tx($0D)
189 |
190 | expected outcome of example usage call: Transmits the byte $0D serially on the txPin
191 | }}
192 |
193 | repeat until (tx_tail <> (tx_head + 1) & $F) 'wait until the buffer has room
194 | tx_buffer[tx_head] := txByte 'place the byte into the buffer
195 | tx_head := (tx_head + 1) & $F 'advance the buffer's pointer
196 |
197 | if rxtx_mode & %1000 'if ignoring rx echo
198 | Rx ' receive the echoed byte and discard
199 |
200 |
201 | PUB Str(stringPtr)
202 | {{
203 | Transmit a string of bytes
204 |
205 | Parameters: stringPtr = the pointer address of the null-terminated string to be sent
206 | return: none
207 |
208 | example usage: serial.Str(@test_string)
209 |
210 | expected outcome of example usage call: Transmits each byte of a string at the address some_string.
211 | }}
212 |
213 | repeat strsize(stringPtr)
214 | Tx(byte[stringPtr++]) 'Transmit each byte in the string
215 |
216 |
217 | PUB Dec(value) | i, x
218 | {{
219 | Transmit the ASCII string equivalent of a decimal value
220 |
221 | Parameters: dec = the numeric value to be transmitted
222 | return: none
223 |
224 | example usage: serial.Dec(-1_234_567_890)
225 |
226 | expected outcome of example usage call: Will print the string "-1234567890" to a listening terminal.
227 | }}
228 |
229 | x := value == NEGX 'Check for max negative
230 | if value < 0
231 | value := ||(value+x) 'If negative, make positive; adjust for max negative
232 | Tx("-") 'and output sign
233 |
234 | i := 1_000_000_000 'Initialize divisor
235 |
236 | repeat 10 'Loop for 10 digits
237 | if value => i
238 | Tx(value / i + "0" + x*(i == 1)) 'If non-zero digit, output digit; adjust for max negative
239 | value //= i 'and digit from value
240 | result~~ 'flag non-zero found
241 | elseif result or i == 1
242 | Tx("0") 'If zero digit (or only digit) output it
243 | i /= 10 'Update divisor
244 |
245 |
246 | PUB Hex(value, digits)
247 | {{
248 | Transmit the ASCII string equivalent of a hexadecimal number
249 |
250 | Parameters: value = the numeric hex value to be transmitted
251 | digits = the number of hex digits to print
252 | return: none
253 |
254 | example usage: serial.Hex($AA_FF_43_21, 8)
255 |
256 | expected outcome of example usage call: Will print the string "AAFF4321" to a listening terminal.
257 | }}
258 |
259 | value <<= (8 - digits) << 2
260 | repeat digits 'do it for the number of hex digits being transmitted
261 | Tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))' Transmit the ASCII value of the hex characters
262 |
263 |
264 | PUB Bin(value, digits)
265 | {{
266 | Transmit the ASCII string equivalent of a binary number
267 |
268 | Parameters: value = the numeric binary value to be transmitted
269 | digits = the number of binary digits to print
270 | return: none
271 |
272 | example usage: serial.Bin(%1110_0011_0000_1100_1111_1010_0101_1111, 32)
273 |
274 | expected outcome of example usage call: Will print the string "11100011000011001111101001011111" to a listening terminal.
275 | }}
276 |
277 | value <<= 32 - digits
278 | repeat digits
279 | Tx((value <-= 1) & 1 + "0") 'Transmit the ASCII value of each binary digit
280 |
281 |
282 | DAT
283 |
284 | '***********************************
285 | '* Assembly language serial driver *
286 | '***********************************
287 |
288 | org
289 | '
290 | '
291 | ' Entry
292 | '
293 | entry mov t1,par 'get structure address
294 | add t1,#4 << 2 'skip past heads and tails
295 |
296 | rdlong t2,t1 'get rx_pin
297 | mov rxmask,#1
298 | shl rxmask,t2
299 |
300 | add t1,#4 'get tx_pin
301 | rdlong t2,t1
302 | mov txmask,#1
303 | shl txmask,t2
304 |
305 | add t1,#4 'get rxtx_mode
306 | rdlong rxtxmode,t1
307 |
308 | add t1,#4 'get bit_ticks
309 | rdlong bitticks,t1
310 |
311 | add t1,#4 'get buffer_ptr
312 | rdlong rxbuff,t1
313 | mov txbuff,rxbuff
314 | add txbuff,#16
315 |
316 | test rxtxmode,#%100 wz 'init tx pin according to mode
317 | test rxtxmode,#%010 wc
318 | if_z_ne_c or outa,txmask
319 | if_z or dira,txmask
320 |
321 | mov txcode,#transmit 'initialize ping-pong multitasking
322 | '
323 | '
324 | ' Receive
325 | '
326 | receive jmpret rxcode,txcode 'run a chunk of transmit code, then return
327 |
328 | test rxtxmode,#%001 wz 'wait for start bit on rx pin
329 | test rxmask,ina wc
330 | if_z_eq_c jmp #receive
331 |
332 | mov rxbits,#9 'ready to receive byte
333 | mov rxcnt,bitticks
334 | shr rxcnt,#1
335 | add rxcnt,cnt
336 |
337 | :bit add rxcnt,bitticks 'ready next bit period
338 |
339 | :wait jmpret rxcode,txcode 'run a chuck of transmit code, then return
340 |
341 | mov t1,rxcnt 'check if bit receive period done
342 | sub t1,cnt
343 | cmps t1,#0 wc
344 | if_nc jmp #:wait
345 |
346 | test rxmask,ina wc 'receive bit on rx pin
347 | rcr rxdata,#1
348 | djnz rxbits,#:bit
349 |
350 | shr rxdata,#32-9 'justify and trim received byte
351 | and rxdata,#$FF
352 | test rxtxmode,#%001 wz 'if rx inverted, invert byte
353 | if_nz xor rxdata,#$FF
354 |
355 | rdlong t2,par 'save received byte and inc head
356 | add t2,rxbuff
357 | wrbyte rxdata,t2
358 | sub t2,rxbuff
359 | add t2,#1
360 | and t2,#$0F
361 | wrlong t2,par
362 |
363 | jmp #receive 'byte done, receive next byte
364 | '
365 | '
366 | ' Transmit
367 | '
368 | transmit jmpret txcode,rxcode 'run a chunk of receive code, then return
369 |
370 | mov t1,par 'check for head <> tail
371 | add t1,#2 << 2
372 | rdlong t2,t1
373 | add t1,#1 << 2
374 | rdlong t3,t1
375 | cmp t2,t3 wz
376 | if_z jmp #transmit
377 |
378 | add t3,txbuff 'get byte and inc tail
379 | rdbyte txdata,t3
380 | sub t3,txbuff
381 | add t3,#1
382 | and t3,#$0F
383 | wrlong t3,t1
384 |
385 | or txdata,#$100 'ready byte to transmit
386 | shl txdata,#2
387 | or txdata,#1
388 | mov txbits,#11
389 | mov txcnt,cnt
390 |
391 | :bit test rxtxmode,#%100 wz 'output bit on tx pin according to mode
392 | test rxtxmode,#%010 wc
393 | if_z_and_c xor txdata,#1
394 | shr txdata,#1 wc
395 | if_z muxc outa,txmask
396 | if_nz muxnc dira,txmask
397 | add txcnt,bitticks 'ready next cnt
398 |
399 | :wait jmpret txcode,rxcode 'run a chunk of receive code, then return
400 |
401 | mov t1,txcnt 'check if bit transmit period done
402 | sub t1,cnt
403 | cmps t1,#0 wc
404 | if_nc jmp #:wait
405 |
406 | djnz txbits,#:bit 'another bit to transmit?
407 |
408 | jmp #transmit 'byte done, transmit next byte
409 | '
410 | '
411 | ' Uninitialized data
412 | '
413 | t1 res 1
414 | t2 res 1
415 | t3 res 1
416 |
417 | rxtxmode res 1
418 | bitticks res 1
419 |
420 | rxmask res 1
421 | rxbuff res 1
422 | rxdata res 1
423 | rxbits res 1
424 | rxcnt res 1
425 | rxcode res 1
426 |
427 | txmask res 1
428 | txbuff res 1
429 | txdata res 1
430 | txbits res 1
431 | txcnt res 1
432 | txcode res 1
433 |
434 |
435 | DAT
436 | {{
437 | ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
438 | │ TERMS OF USE: MIT License │
439 | ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
440 | │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
441 | │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
442 | │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
443 | │is furnished to do so, subject to the following conditions: │
444 | │ │
445 | │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
446 | │ │
447 | │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
448 | │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
449 | │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
450 | │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
451 | └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
452 | }}
--------------------------------------------------------------------------------
/software/python/library/src/serialio/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | openspin -b -o serialio.binary serialio.spin
3 |
4 | clean:
5 | rm *.binary
6 |
--------------------------------------------------------------------------------
/software/python/library/src/serialio/serialio.spin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/software/python/library/src/serialio/serialio.spin
--------------------------------------------------------------------------------
/software/python/packaging/CHANGELOG:
--------------------------------------------------------------------------------
1 | p1 (1.0.1) UNRELEASED; urgency=low
2 |
3 | * Ready for Propeller HAT launch
4 |
5 | -- Phil Howard Mon, 23 Feb 2015 00:00:00 +0000
6 |
--------------------------------------------------------------------------------
/software/python/packaging/debian/README:
--------------------------------------------------------------------------------
1 | README
2 |
3 | Propeller HAT brings the 8-core Parallax Propeller microcontroller to the Raspberry Pi. You can program and talk to it over Serial using the Propeller IDE.
4 |
5 | Learn more: https://shop.pimoroni.com/products/propeller-hat
6 | For examples run: `curl -sS get.pimoroni.com/propellerhat | bash`
7 |
--------------------------------------------------------------------------------
/software/python/packaging/debian/changelog:
--------------------------------------------------------------------------------
1 | p1 (1.0.1) UNRELEASED; urgency=low
2 |
3 | * Ready for Propeller HAT launch
4 |
5 | -- Phil Howard Mon, 23 Feb 2015 00:00:00 +0000
6 |
--------------------------------------------------------------------------------
/software/python/packaging/debian/clean:
--------------------------------------------------------------------------------
1 | *.egg-info/*
2 |
--------------------------------------------------------------------------------
/software/python/packaging/debian/compat:
--------------------------------------------------------------------------------
1 | 9
2 |
--------------------------------------------------------------------------------
/software/python/packaging/debian/control:
--------------------------------------------------------------------------------
1 | Source: p1
2 | Maintainer: Phil Howard
3 | Homepage: https://github.com/pimoroni/propeller-hat
4 | Section: python
5 | Priority: extra
6 | Build-Depends: debhelper (>= 9.0.0), dh-python, python-all (>= 2.7), python-setuptools, python3-all (>= 3.4), python3-setuptools
7 | Standards-Version: 3.9.6
8 | X-Python-Version: >= 2.7
9 | X-Python3-Version: >= 3.4
10 |
11 | Package: python-propellerhat
12 | Architecture: all
13 | Section: python
14 | Depends: ${misc:Depends}, ${python:Depends}, python-rpi.gpio, python-serial (>= 2.6)
15 | Description: python library for uploading code to Propeller HAT
16 | Propeller HAT brings the 8-core Parallax Propeller microcontroller
17 | to the Raspberry Pi.
18 | .
19 | This is the Python 2 version of the package.
20 |
21 | Package: python3-propellerhat
22 | Architecture: all
23 | Section: python
24 | Depends: ${misc:Depends}, ${python3:Depends}, python3-rpi.gpio, python3-serial (>= 2.6)
25 | Description: python library for uploading code to Propeller HAT
26 | Propeller HAT brings the 8-core Parallax Propeller microcontroller
27 | to the Raspberry Pi.
28 | .
29 | This is the Python 3 version of the package.
30 |
--------------------------------------------------------------------------------
/software/python/packaging/debian/copyright:
--------------------------------------------------------------------------------
1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2 | Upstream-Name: p1
3 | Source: https://github.com/pimoroni/propeller-hat
4 |
5 | Files: *
6 | Copyright: 2016 Pimoroni Ltd
7 | License: MIT
8 |
9 | License: MIT
10 | Permission is hereby granted, free of charge, to any person obtaining a copy
11 | of this software and associated documentation files (the "Software"), to deal
12 | in the Software without restriction, including without limitation the rights
13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | copies of the Software, and to permit persons to whom the Software is
15 | furnished to do so, subject to the following conditions:
16 | .
17 | The above copyright notice and this permission notice shall be included in
18 | all copies or substantial portions of the Software.
19 | .
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | THE SOFTWARE.
27 |
--------------------------------------------------------------------------------
/software/python/packaging/debian/docs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/software/python/packaging/debian/docs
--------------------------------------------------------------------------------
/software/python/packaging/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 | # -*- makefile -*-
3 |
4 | #export DH_VERBOSE=1
5 | export DH_OPTIONS
6 |
7 | %:
8 | dh $@ --with python2,python3 --buildsystem=python_distutils
9 |
10 | override_dh_auto_install:
11 | python setup.py install --root debian/python-propellerhat --install-layout=deb
12 | python3 setup.py install --root debian/python3-propellerhat --install-layout=deb
13 |
--------------------------------------------------------------------------------
/software/python/packaging/debian/source/format:
--------------------------------------------------------------------------------
1 | 3.0 (native)
2 |
--------------------------------------------------------------------------------
/software/python/packaging/debian/source/options:
--------------------------------------------------------------------------------
1 | extend-diff-ignore = "^[^/]+\.egg-info/"
2 |
--------------------------------------------------------------------------------
/software/python/packaging/makeall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # script control variables
4 |
5 | reponame="propeller-hat" # leave this blank for auto-detection
6 | libname="" # leave this blank for auto-detection
7 | packagename="propellerhat" # leave this blank for auto-selection
8 |
9 | debianlog="debian/changelog"
10 | debcontrol="debian/control"
11 | debcopyright="debian/copyright"
12 | debrules="debian/rules"
13 | debreadme="debian/README"
14 |
15 | debdir="$(pwd)"
16 | rootdir="$(dirname $debdir)"
17 | libdir="$rootdir/library"
18 |
19 | FLAG=false
20 |
21 | # function define
22 |
23 | success() {
24 | echo "$(tput setaf 2)$1$(tput sgr0)"
25 | }
26 |
27 | inform() {
28 | echo "$(tput setaf 6)$1$(tput sgr0)"
29 | }
30 |
31 | warning() {
32 | echo "$(tput setaf 1)$1$(tput sgr0)"
33 | }
34 |
35 | newline() {
36 | echo ""
37 | }
38 |
39 | # assessing repo and library variables
40 |
41 | if [ -z "$reponame" ] || [ -z "$libname" ]; then
42 | inform "detecting reponame and libname..."
43 | else
44 | inform "using reponame and libname overrides"
45 | fi
46 |
47 | if [ -z "$reponame" ]; then
48 | if [[ $rootdir == *"python"* ]]; then
49 | repodir="$(dirname $rootdir)"
50 | reponame="$(basename $repodir)"
51 | else
52 | repodir="$rootdir"
53 | reponame="$(basename $repodir)"
54 | fi
55 | reponame=$(echo "$reponame" | tr "[A-Z]" "[a-z]")
56 | fi
57 |
58 | if [ -z "$libname" ]; then
59 | cd "$libdir"
60 | libname=$(grep "name" setup.py | tr -d "[:space:]" | cut -c 7- | rev | cut -c 3- | rev)
61 | libname=$(echo "$libname" | tr "[A-Z]" "[a-z]") && cd "$debdir"
62 | fi
63 |
64 | if [ -z "$packagename" ]; then
65 | packagename="$libname"
66 | fi
67 |
68 | echo "reponame is $reponame and libname is $libname"
69 | echo "output packages will be python-$packagename and python3-$packagename"
70 |
71 | # checking generating changelog file
72 |
73 | ./makelog.sh
74 | version=$(head -n 1 "$libdir/CHANGELOG.txt")
75 | echo "building $libname version $version"
76 |
77 | # checking debian/changelog file
78 |
79 | inform "checking debian/changelog file..."
80 |
81 | if ! head -n 1 $debianlog | grep "$libname" &> /dev/null; then
82 | warning "library not mentioned in header!" && FLAG=true
83 | elif head -n 1 $debianlog | grep "UNRELEASED"; then
84 | warning "this changelog is not going to generate a release!"
85 | warning "change distribution to 'stable'" && FLAG=true
86 | fi
87 |
88 | # checking debian/copyright file
89 |
90 | inform "checking debian/copyright file..."
91 |
92 | if ! grep "^Source" $debcopyright | grep "$reponame" &> /dev/null; then
93 | warning "$(grep "^Source" $debcopyright)" && FLAG=true
94 | fi
95 |
96 | if ! grep "^Upstream-Name" $debcopyright | grep "$libname" &> /dev/null; then
97 | warning "$(grep "^Upstream-Name" $debcopyright)" && FLAG=true
98 | fi
99 |
100 | # checking debian/control file
101 |
102 | inform "checking debian/control file..."
103 |
104 | if ! grep "^Source" $debcontrol | grep "$libname" &> /dev/null; then
105 | warning "$(grep "^Source" $debcontrol)" && FLAG=true
106 | fi
107 |
108 | if ! grep "^Homepage" $debcontrol | grep "$reponame" &> /dev/null; then
109 | warning "$(grep "^Homepage" $debcontrol)" && FLAG=true
110 | fi
111 |
112 | if ! grep "^Package: python-$packagename" $debcontrol &> /dev/null; then
113 | warning "$(grep "^Package: python-" $debcontrol)" && FLAG=true
114 | fi
115 |
116 | if ! grep "^Package: python3-$packagename" $debcontrol &> /dev/null; then
117 | warning "$(grep "^Package: python3-" $debcontrol)" && FLAG=true
118 | fi
119 |
120 | if ! grep "^Priority: extra" $debcontrol &> /dev/null; then
121 | warning "$(grep "^Priority" $debcontrol)" && FLAG=true
122 | fi
123 |
124 |
125 | # checking debian/rules file
126 |
127 | inform "checking debian/rules file..."
128 |
129 | if ! grep "debian/python-$packagename" $debrules &> /dev/null; then
130 | warning "$(grep "debian/python-" $debrules)" && FLAG=true
131 | fi
132 |
133 | if ! grep "debian/python3-$packagename" $debrules &> /dev/null; then
134 | warning "$(grep "debian/python3-" $debrules)" && FLAG=true
135 | fi
136 |
137 | # checking debian/README file
138 |
139 | inform "checking debian/readme file..."
140 |
141 | if ! grep -e "$libname" -e "$reponame" $debreadme &> /dev/null; then
142 | warning "README does not seem to mention product, repo or lib!" && FLAG=true
143 | fi
144 |
145 | # summary of checks pre build
146 |
147 | if $FLAG; then
148 | warning "Check all of the above and correct!" && exit 1
149 | else
150 | inform "we're good to go... bulding!"
151 | fi
152 |
153 | # building deb and final checks
154 |
155 | ./makedeb.sh
156 |
157 | inform "running lintian..."
158 | lintian -v $(find -name "python*$version*.deb")
159 | lintian -v $(find -name "python3*$version*.deb")
160 |
161 | inform "checking signatures..."
162 | gpg --verify $(find -name "*$version*changes")
163 | gpg --verify $(find -name "*$version*dsc")
164 |
165 | exit 0
166 |
--------------------------------------------------------------------------------
/software/python/packaging/makedeb.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | gettools="no"
4 | setup="yes"
5 | cleanup="yes"
6 | pkgfiles=( "build" "changes" "deb" "dsc" "tar.xz" )
7 |
8 |
9 | if [ $gettools == "yes" ]; then
10 | sudo apt-get update && sudo apt-get install build-essential debhelper devscripts dh-make dh-python dput gnupg
11 | sudo apt-get install python-all python-setuptools python3-all python3-setuptools
12 | fi
13 |
14 | if [ $setup == "yes" ]; then
15 | rm -R ../library/build ../library/debian &> /dev/null
16 | cp -R ./debian/ ../library/
17 | fi
18 |
19 | cd ../library && debuild -aarmhf
20 |
21 | for file in ${pkgfiles[@]}; do
22 | mv ../*.$file ../packaging
23 | done
24 |
25 | if [ $cleanup == "yes" ]; then
26 | debuild clean
27 | rm -R ./build ./debian &> /dev/null
28 | fi
29 |
30 | exit 0
31 |
--------------------------------------------------------------------------------
/software/python/packaging/makelog.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # script control variables
4 |
5 | libname="" # leave this blank for auto-detection
6 | sibname=() # name of sibling in packages list
7 | versionwarn="yes" # set to anything but 'yes' to turn off warning
8 |
9 | debdir="$(pwd)"
10 | rootdir="$(dirname $debdir)"
11 | libdir="$rootdir/library"
12 |
13 | mainlog="CHANGELOG"
14 | debianlog="debian/changelog"
15 | pypilog="$libdir/CHANGELOG.txt"
16 |
17 | # function define
18 |
19 | success() {
20 | echo "$(tput setaf 2)$1$(tput sgr0)"
21 | }
22 |
23 | inform() {
24 | echo "$(tput setaf 6)$1$(tput sgr0)"
25 | }
26 |
27 | warning() {
28 | echo "$(tput setaf 1)$1$(tput sgr0)"
29 | }
30 |
31 | newline() {
32 | echo ""
33 | }
34 |
35 | # generate debian changelog
36 |
37 | cat $mainlog > $debianlog
38 | inform "seeded debian changelog"
39 |
40 | # generate pypi changelog
41 |
42 | sed -e "/--/d" -e "s/ \*/\*/" \
43 | -e "s/.*\([0-9].[0-9].[0-9]\).*/\1/" \
44 | -e '/[0-9].[0-9].[0-9]/ a\
45 | -----' $mainlog | cat -s > $pypilog
46 |
47 | version=$(head -n 1 $pypilog)
48 | inform "pypi changelog generated"
49 |
50 | # touch up version in setup.py file
51 |
52 | if [ -n $(grep version "$libdir/setup.py" &> /dev/null) ]; then
53 | inform "touched up version in setup.py"
54 | sed -i "s/'[0-9].[0-9].[0-9]'/'$version'/" "$libdir/setup.py"
55 | else
56 | warning "couldn't touch up version in setup, no match found"
57 | fi
58 |
59 | # touch up version in lib or package siblings
60 |
61 | if [ -z "$libname" ]; then
62 | cd "$libdir"
63 | libname=$(grep "name" setup.py | tr -d "[:space:]" | cut -c 7- | rev | cut -c 3- | rev)
64 | libname=$(echo "$libname" | tr "[A-Z]" "[a-z]") && cd "$debdir"
65 | sibname+=( "$libname" )
66 | elif [ "$libname" != "package" ]; then
67 | sibname+=( "$libname" )
68 | fi
69 |
70 | for sibling in ${sibname[@]}; do
71 | if grep -e "__version__" "$libdir/$sibling.py" &> /dev/null; then
72 | sed -i "s/__version__ = '[0-9].[0-9].[0-9]'/__version__ = '$version'/" "$libdir/$sibling.py"
73 | inform "touched up version in $sibling.py"
74 | elif grep -e "__version__" "$libdir/$sibling/__init__.py" &> /dev/null; then
75 | sed -i "s/__version__ = '[0-9].[0-9].[0-9]'/__version__ = '$version'/" "$libdir/$sibling/__init__.py"
76 | inform "touched up version in $sibling/__init__.py"
77 | elif [ "$versionwarn" == "yes" ]; then
78 | warning "couldn't touch up __version__ in $sibling, no match found"
79 | fi
80 | done
81 |
82 | exit 0
83 |
--------------------------------------------------------------------------------
/software/python/tools/binarytoarray.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import sys
4 |
5 |
6 | f = open(sys.argv[1],"rb")
7 | b = f.read()
8 | f.close()
9 | b = list(b)
10 | b = map(ord,b)
11 | b = map(hex,b)
12 | print(",".join(b))
13 |
--------------------------------------------------------------------------------
/software/python/tools/io.arr:
--------------------------------------------------------------------------------
1 | 0x0,0xd8,0xb8,0x5,0x6f,0xbf,0x10,0x0,0x7c,0x2,0x90,0x3,0x1c,0x0,0x98,0x3,0x54,0x0,0x2,0x1,0xc,0x0,0x4,0x0,0x54,0x0,0x4,0x0,0x1,0x38,0x1a,0x38,0x1b,0x38,0x17,0x6,0x2,0x1,0x35,0x65,0x35,0x64,0x3d,0xb6,0x35,0x64,0x3d,0xb4,0x35,0x37,0x24,0x66,0x2,0x72,0x35,0x65,0x0,0x64,0x37,0x4,0xec,0x6,0x2,0x9,0x36,0xfc,0x64,0x3d,0xb6,0x0,0x64,0x6,0x2,0x9,0x36,0xfc,0x64,0x3d,0xb4,0x1,0x64,0x37,0x5,0xec,0x64,0x3d,0x92,0x6,0x2,0xa,0x35,0x38,0x1b,0x66,0x2,0x58,0x4,0x54,0x32,0x0,0x18,0x2,0xc,0x0,0xac,0x1,0x0,0x0,0xc5,0x1,0x0,0x0,0xd2,0x1,0x0,0x0,0xd6,0x1,0x0,0x0,0xe2,0x1,0x0,0x0,0xf5,0x1,0x0,0x0,0xf8,0x1,0x0,0x0,0xfe,0x1,0x0,0x0,0x5,0x2,0x0,0x0,0xa,0x2,0x0,0x0,0xf,0x2,0x4,0x0,0xf0,0xd1,0xbc,0xa0,0x68,0xca,0xbc,0xa0,0x4,0xd0,0xfc,0x80,0x68,0xc4,0xbc,0x0,0x1,0xc4,0xfc,0x2c,0x1,0xd0,0xfc,0x80,0x68,0xd2,0xbc,0x0,0x1,0xbe,0xfc,0xa0,0x69,0xbe,0xbc,0x2c,0x1,0xd0,0xfc,0x80,0x68,0xd2,0xbc,0x0,0x1,0xc0,0xfc,0xa0,0x69,0xc0,0xbc,0x2c,0x1,0xd0,0xfc,0x80,0x68,0xc6,0xbc,0xa0,0x5f,0xc2,0xbc,0xa0,0x60,0xc2,0xbc,0x68,0x61,0xc2,0x3c,0xf0,0x60,0xc0,0x3c,0xf4,0xf2,0xbf,0x3c,0x61,0x11,0x0,0x4c,0x5c,0x31,0x8e,0xfc,0x5c,0x66,0xd0,0xbc,0xa0,0xfe,0xd0,0xfc,0x60,0x62,0xd0,0x3c,0x86,0x11,0x0,0x54,0x5c,0x59,0xbc,0xfc,0x5c,0x1,0xcc,0x7c,0x61,0x21,0x0,0x4c,0x5c,0x4a,0xb0,0xfc,0x5c,0x1,0xc8,0xfc,0x80,0x1d,0x0,0x4c,0x5c,0x11,0x0,0x7c,0x5c,0x65,0xd0,0xbc,0x8,0x1,0xd2,0xfc,0xa0,0x63,0xc8,0xbc,0xa0,0x31,0x8e,0xfc,0x5c,0x66,0xc8,0xbc,0x80,0x66,0xd2,0xbc,0x2c,0x59,0xbc,0xfc,0x5c,0x69,0xd0,0xbc,0x68,0x31,0x8e,0xfc,0x5c,0x64,0xcc,0x3c,0x0,0x1,0xc8,0xfc,0x80,0x69,0xd0,0xbc,0x68,0x65,0xd0,0x3c,0x8,0x1,0xd2,0xfc,0x2c,0x59,0xbc,0xfc,0x5c,0x29,0x0,0x7c,0x5c,0x7,0xce,0xfc,0xa0,0x0,0xcc,0xfc,0xa0,0x5f,0xbe,0x3c,0xf4,0x5f,0xbe,0x3c,0xf0,0xf2,0xc1,0x3c,0x61,0x1,0xcc,0xfc,0x34,0x3d,0x0,0x70,0x5c,0xf2,0xbf,0x3c,0x62,0x42,0x0,0x68,0x5c,0xf2,0xc1,0x3c,0x62,0x48,0x0,0x54,0x5c,0x38,0x0,0x7c,0x5c,0xf2,0xbf,0x3c,0x62,0x42,0x0,0x68,0x5c,0xf2,0xc1,0x3c,0x62,0x15,0x0,0x68,0x5c,0x3d,0x0,0x7c,0x5c,0x5f,0xbe,0x3c,0xf4,0x5f,0xbe,0x3c,0xf0,0xf2,0xc1,0x3c,0x61,0x1,0xcc,0xfc,0x34,0x42,0xce,0xfc,0xe4,0x0,0x0,0x7c,0x5c,0x65,0xd0,0x3c,0x8,0x11,0x0,0x7c,0x5c,0x8,0xce,0xfc,0xa0,0x64,0xcc,0xbc,0x0,0x18,0xcc,0xfc,0x2c,0x5f,0xbe,0x3c,0xf4,0x1,0xcc,0xfc,0x2d,0x60,0xec,0xbf,0x74,0x5f,0xbe,0x3c,0xf0,0x5f,0xbe,0x3c,0xf4,0x4d,0xce,0xfc,0xe4,0x60,0xec,0xbf,0x64,0x5f,0xbe,0x3c,0xf4,0x5f,0xbe,0x3c,0xf0,0xf2,0xc1,0x3c,0x61,0x5f,0xbe,0x3c,0xf4,0x0,0x0,0x7c,0x5c,0x5f,0xbe,0x3c,0xf4,0x60,0xec,0xbf,0x68,0x5f,0xbe,0x3c,0xf0,0x5f,0xbe,0x3c,0xf4,0x60,0xec,0xbf,0x64,0x0,0x0,0x7c,0x5c,0x1,0x5,0x2,0x6c,0x89,0x4,0x64,0x89,0x5,0x68,0x89,0x6,0x34,0xc7,0x30,0x43,0x28,0x36,0xec,0x8a,0x81,0x7,0x80,0x61,0x32,0x88,0x81,0x7,0xa,0x7,0x8a,0x81,0x7,0x98,0x36,0xed,0x21,0x32,0x8b,0x7,0x33,0x32,0x40,0xf1,0x36,0xed,0x61,0x40,0x60,0xf3,0xe7,0xe8,0x41,0x32,0x64,0xf3,0x40,0xe8,0xa,0xa,0x40,0x64,0xf3,0xe7,0xe8,0x41,0x64,0x98,0x7,0x33,0x34,0x33,0x32,0x40,0x33,0x32,0x64,0xf3,0x40,0xe8,0x33,0x32,0x40,0x64,0xf3,0xe7,0xe8,0x41,0x32,0x64,0x98,0x7,0x33,0x32,0x68,0x64,0x99,0x7,0x32,0x42,0x18,0x8b,0x7,0x35,0x37,0x7,0x18,0x32
2 |
--------------------------------------------------------------------------------
/software/python/tools/lfsr.py:
--------------------------------------------------------------------------------
1 | """Propeller LFSR Byte Packer
2 |
3 | 1 = t | 0111111111
4 | 0 = 2t | 0011111111
5 |
6 | """
7 | LFSR_SEED = ord("P")
8 |
9 | def lfsr(seed):
10 | """Generate bits from 8-bit LFSR with taps at 0xB2."""
11 | while True:
12 | yield seed & 0x01
13 | seed = ((seed << 1) & 0xfe) | (((seed >> 7) ^ (seed >> 5) ^ (seed >> 4) ^ (seed >> 1)) & 1)
14 |
15 | lfsr_seq = []
16 | for (i, value) in zip(range(500), lfsr(LFSR_SEED)):
17 | lfsr_seq.append(value)
18 |
19 | handshake = [1,0]
20 |
21 | handshake += lfsr_seq[:250]
22 |
23 | '''
24 | handshake.append('C')
25 |
26 | for i in range(258):
27 | handshake.append(1)
28 | handshake.append(0)
29 |
30 | response = lfsr_seq[249:]
31 | '''
32 |
33 |
34 | """Serial has a start bit which is always 0
35 | Serial has a stop bit which is, by necessity, always 1
36 |
37 | Between these bits we have 8 bits we can toggle.
38 |
39 | 0________1
40 |
41 | Within this scheme we can pack 5 low pulses of length t like so:
42 |
43 | 0101010101
44 | _-_-_-_-_-
45 |
46 | Or 3 low pulses of length 2t like so:
47 |
48 | 0010010011
49 | __-__-__--
50 | """
51 |
52 | def pack_bitstream(seq):
53 | packed = ['']
54 | bit = None
55 | while len(seq):
56 | byte = packed[len(packed)-1]
57 | if bit == None:
58 | bit = seq.pop(0)
59 | if bit == 'C':
60 | packed[len(packed)-1] = '1' * 8
61 | packed.append('')
62 | bit = None
63 | continue
64 | if bit: # We have a 1, t, or '0'
65 | if len(byte) == 0:
66 | byte += '1'
67 | packed[len(packed)-1] = byte
68 | bit = None
69 | continue
70 |
71 | # Pass the bit onto the next byte
72 | if len(byte) == 8:
73 | packed.append('')
74 | continue
75 |
76 | byte += '0'
77 | if len(byte) < 8:
78 | byte += '1'
79 |
80 | packed[len(packed)-1] = byte
81 | bit = None
82 |
83 | if len(byte) == 8 and len(seq) > 0:
84 | packed.append('')
85 |
86 | else: # We have a 2, 2t, or '00'
87 | if len(byte) == 0:
88 | byte += '01'
89 | packed[len(packed)-1] = byte
90 | bit = None
91 | continue
92 |
93 | if len(byte) > 6:
94 | packed[len(packed)-1] = byte.ljust(8,'1')
95 | packed.append('')
96 | continue
97 |
98 | byte += '00'
99 | if len(byte) < 8:
100 | byte += '1'
101 |
102 | packed[len(packed)-1] = byte
103 | bit = None
104 |
105 | if len(byte) == 8 and len(seq) > 0:
106 | packed.append('')
107 |
108 | packed[len(packed)-1] = packed[len(packed)-1].ljust(8,'1')
109 |
110 | #print(len(packed))
111 | print('0' + '1,0'.join(packed) + '1')
112 | return list(int(i[::-1],2) for i in packed)
113 |
114 | print(handshake)
115 | print(','.join(hex(i) for i in pack_bitstream(handshake)))
116 |
117 | '''
118 | print(response)
119 | print(','.join(hex(i) for i in pack_bitstream(response)))
120 | '''
121 |
122 | exit()
123 |
124 | f = open('Analog.binary','rb')
125 | binary = f.read()
126 | f.close()
127 |
128 | byte_len = len(binary)
129 |
130 |
131 | def column(title, text):
132 | print(title.ljust(30) + ': ' + text)
133 |
134 | column('Binary file length', str(byte_len) + ' bytes')
135 |
136 | bit_list = []
137 | for byte in binary:
138 | b = list(bin(ord(byte)).replace('0b','').rjust(8,'0'))
139 | bit_list += b
140 |
141 |
142 | bit_list = map(int,bit_list)
143 |
144 | bit_len = len(bit_list)
145 |
146 | column( 'Length in (above*8)', str(bit_len) + ' bits')
147 |
148 | #print(bit_list)
149 |
150 | #print(','.join(hex(i) for i in pack_bitstream(bit_list)))
151 |
152 | packed_stream = pack_bitstream(bit_list)
153 |
154 | packed_len = len(packed_stream)
155 |
156 | column( 'Packed lenth', str(packed_len) + ' bytes')
157 |
158 | column( 'Compression factor from bits', str( float(bit_len)/float(packed_len) ) )
159 | column( 'Compression factor from bytes', str( float(packed_len)/float(byte_len) ) )
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/software/sidplay/README.md:
--------------------------------------------------------------------------------
1 | #SIDPlay
2 |
3 | This example uses SIDcog Serial Slave and a serial streamer written in C to stream raw SID register dumps to Propeller HAT.
4 |
5 | You will need to install wiringPi!
6 |
7 | ```bash
8 | git clone git://git.drogon.net/wiringPi
9 | cd wiringPi
10 | ./build
11 | ```
12 |
13 | To upload the sid player, run:
14 |
15 | ./sidplay.py
16 |
17 | To play a SID dump, run:
18 |
19 | ./sidplay SID_File [Frequenzy_HZ Duration_Sec]
20 |
21 | To create a valid dump file you will need the SID dumper tool from here: http://forums.parallax.com/showthread.php/118285-SIDcog-The-sound-of-the-Commodore-64-!-%28Now-in-the-OBEX%29
22 |
--------------------------------------------------------------------------------
/software/sidplay/playlist.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import subprocess
4 | import time
5 | from sys import exit, version_info
6 |
7 | try:
8 | import smbus
9 | except ImportError:
10 | if version_info[0] < 3:
11 | exit("This library requires python-smbus\nInstall with: sudo apt-get install python-smbus")
12 | elif version_info[0] == 3:
13 | exit("This library requires python3-smbus\nInstall with: sudo apt-get install python3-smbus")
14 |
15 | try:
16 | import RPi.GPIO as GPIO
17 | except ImportError:
18 | exit("This library requires the RPi.GPIO module\nInstall with: sudo pip install RPi.GPIO")
19 |
20 |
21 | GPIO.setmode(GPIO.BCM)
22 | GPIO.setup(17,GPIO.OUT,initial=GPIO.HIGH)
23 | GPIO.output(17,GPIO.LOW)
24 | time.sleep(0.01)
25 | GPIO.output(17,GPIO.HIGH)
26 | time.sleep(1)
27 |
28 | bus = smbus.SMBus(1)
29 |
30 | #proc = subprocess.Popen(['p1load','-e','-r','SIDcogSlave.binary'])
31 | #proc.wait()
32 |
33 | duration = 120
34 |
35 | # File, Time seconds, speed hz
36 | playlist = [
37 | ('Eskimonika',220,250),
38 | ('Boten_Anna',100,duration),
39 | ('All_That_She_Wants_8580',120,duration),
40 | ('Scream',60,duration),
41 | ('Polyphonica',60,50),
42 | ('Alternative_Fuel',50,duration),
43 | ('Vibralux',50,duration),
44 | ('Super_Mario_Land',50,duration)
45 | ]
46 |
47 | proc = None
48 |
49 | while True:
50 | for song, speed, duration in playlist:
51 | print("Playing {} for {}".format(song, duration))
52 | proc = subprocess.Popen(['./sidplay','sid/{}.dmp'.format(song),str(speed),str(duration)])
53 | while proc.poll() is None:
54 | try:
55 | button = bus.read_byte_data(0x14,0x00)
56 | if button:
57 | proc.kill()
58 | while bus.read_byte_data(0x14,0x00):
59 | pass
60 | continue
61 | except IOError:
62 | pass
63 | time.sleep(0.01)
64 |
--------------------------------------------------------------------------------
/software/sidplay/sidplay:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/software/sidplay/sidplay
--------------------------------------------------------------------------------
/software/sidplay/sidplay.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import sys
4 | import time
5 |
6 | try:
7 | import serial
8 | except ImportError:
9 | sys.exit("This library requires the serial module\nInstall with: sudo pip install pyserial")
10 |
11 | import p1.loader
12 |
13 |
14 | print('Setting up Propeller HAT')
15 | l = p1.loader.Loader('/dev/ttyAMA0',17)
16 | l.upload(path='SIDcogSlave.binary',progress=p1.loader.print_status)
17 | time.sleep(0.1)
18 |
19 | # Comment the line below to enable the (slow) Python sid player
20 | exit('Now use ./sidplay tunes/ to play a tune!')
21 |
22 | play_rate = 50 #Hz
23 |
24 | if len(sys.argv) < 2:
25 | exit("Usage: " + sys.argv[0] + " ")
26 |
27 | s = serial.Serial('/dev/ttyAMA0',115200)
28 |
29 | f = open(sys.argv[1],'rb')
30 |
31 | d = f.read()
32 |
33 | f.close()
34 |
35 | reg_size = 25
36 |
37 |
38 | def chunks(l, n):
39 | for i in range(0, len(l), n):
40 | yield l[i:i+n]
41 |
42 | chunks = list(map(lambda x: chr(13) + 'SDMP' + ''.join(x), chunks(d, reg_size)))
43 |
44 | for chunk in chunks:
45 | print(list(ord(x) for x in chunk))
46 | s.write(chunk)
47 | s.flush()
48 | time.sleep(1.0/play_rate)
49 |
50 |
--------------------------------------------------------------------------------
/software/sidplay/src/SIDcogSlave/CombinedWaveforms.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/software/sidplay/src/SIDcogSlave/CombinedWaveforms.bin
--------------------------------------------------------------------------------
/software/sidplay/src/SIDcogSlave/FullDuplexSerial.spin:
--------------------------------------------------------------------------------
1 | {{
2 | Object file: FullDuplexSerial.spin
3 | Version: 1.2.1
4 | Date: 2006 - 2011
5 | Author: Chip Gracey, Jeff Martin, Daniel Harris
6 | Company: Parallax Semiconductor
7 | Email: dharris@parallaxsemiconductor.com
8 | Licensing: MIT License - see end of file for terms of use.
9 |
10 | Description:
11 | This driver, once started, implements a serial port in one cog.
12 |
13 | Revision History:
14 | v1.2.1 - 5/1/2011 Added extra comments and demonstration code to bring up
15 | to gold standard.
16 | v1.2 - 5/7/2009 Fixed bug in dec method causing largest negative value
17 | (-2,147,483,648) to be output as -0.
18 | v1.1 - 3/1/2006 First official release.
19 |
20 |
21 | =============================================
22 | Connection Diagram
23 | =============================================
24 |
25 | ┌─────────┐
26 | │ │
27 | │ rxPin├─── TTL level RX line
28 | │ txPin├─── TTL level TX line
29 | │ │
30 | └─────────┘
31 | Propeller
32 | MCU
33 | (P8X32A)
34 |
35 | Components:
36 | N/A
37 |
38 | =============================================
39 | }}
40 |
41 |
42 | VAR
43 |
44 | 'Global variable declarations
45 |
46 | long cog 'cog flag/id
47 |
48 | '9 longs, MUST be contiguous
49 | long rx_head
50 | long rx_tail
51 | long tx_head
52 | long tx_tail
53 | long rx_pin
54 | long tx_pin
55 | long rxtx_mode
56 | long bit_ticks
57 | long buffer_ptr
58 |
59 | byte rx_buffer[16] 'transmit and receive buffers
60 | byte tx_buffer[16] '16 bytes each
61 |
62 |
63 | PUB Start(rxPin, txPin, mode, baudrate) : okay
64 | {{
65 | Start serial driver - starts a cog
66 |
67 |
68 | Parameters: rxPin = Propeller pin to set up as RX-ing pin. Range = 0 - 31
69 | txPin = Propeller pin to set up as TX-ing pin. Range = 0 - 31
70 | mode = bitwise mode configuration variable, see mode bit description below.
71 | baudrate = baud rate to transmit bits at.
72 |
73 | mode bit 0 = invert rx
74 | mode bit 1 = invert tx
75 | mode bit 2 = open-drain/source tx
76 | mode bit 3 = ignore tx echo on rx
77 |
78 | return: Numeric value of the cog(1-8) that was started, false(0) if no cog is available.
79 |
80 | example usage: serial.start(31, 30, %0000, 9_600)
81 |
82 | expected outcome of example usage call: Starts a serial port on Propller pins 30 and 31.
83 | The serial port does not invert the RX and TX data,
84 | no open-drain/source on the TX pin, does not ignore
85 | data echoed on RX pin, at 9,600 baud.
86 | }}
87 |
88 | Stop 'make sure the driver isnt already running
89 | longfill(@rx_head, 0, 4) 'zero out the buffer pointers
90 | longmove(@rx_pin, @rxpin, 3) 'copy the start parameters to this objects pin variables
91 | bit_ticks := clkfreq / baudrate 'number of clock ticks per bit for the desired baudrate
92 | buffer_ptr := @rx_buffer 'save the address of the receive buffer
93 | okay := cog := cognew(@entry, @rx_head) + 1 'start the new cog now, assembly cog at "entry" label.
94 |
95 |
96 | PUB Stop
97 | {{
98 | Stop serial driver if it has already been started - frees the cog
99 |
100 | Parameters: none
101 | return: none
102 |
103 | example usage: serial.stop
104 |
105 | expected outcome of example usage call: Stops an already started serial port.
106 | }}
107 |
108 | if cog
109 | cogstop(cog~ - 1) 'if the driver is already running, stop the cog
110 | longfill(@rx_head, 0, 9) 'zero out configuration variables
111 |
112 |
113 | PUB RxFlush
114 | {{
115 | Continuously pops the head of the receive buffer until no bytes remain.
116 |
117 | Parameters: none
118 | return: none
119 |
120 | example usage: serial.RxFlush
121 |
122 | expected outcome of example usage call: Receive bffer will be cleared.
123 | }}
124 |
125 | repeat while RxCheck => 0 'Call RxCheck until buffer is empty
126 |
127 |
128 | PUB RxCheck : rxByte
129 | {{
130 | Check if a byte is waiting in the receive buffer and return the byte if one is there,
131 | does NOT block (never waits).
132 |
133 | Parameters: none
134 | return: If no byte, then return(-1). If byte, then return(byte).
135 |
136 | example usage: serial.RxCheck
137 |
138 | expected outcome of example usage call: Return a byte if one is available, but dont wait
139 | for a byte to come in.
140 | }}
141 |
142 |
143 | rxByte-- 'make rxbyte = -1
144 | if rx_tail <> rx_head 'if a byte is in the buffer, then
145 | rxByte := rx_buffer[rx_tail] ' grab it and store in rxByte
146 | rx_tail := (rx_tail + 1) & $F ' advance the buffer pointer
147 |
148 |
149 | PUB RxTime(ms) : rxByte | t
150 | {{
151 | Wait ms milliseconds for a byte to be received
152 |
153 | Parameters: ms = number of milliseconds to wait for a byte to be received.
154 | return: If no byte, then return(-1). If byte, then return(byte).
155 |
156 | example usage: serial.RxTime(500)
157 |
158 | expected outcome of example usage call: Wait half a second (500 ms) for a byte to be received.
159 | }}
160 |
161 | t := cnt 'take note of the current time
162 | repeat until (rxByte := RxCheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms
163 |
164 |
165 | PUB Rx : rxByte
166 | {{
167 | Receive byte (may wait for byte)
168 | returns $00..$FF
169 |
170 | Parameters: none
171 | return: received byte
172 |
173 | example usage: serial.Rx
174 |
175 | expected outcome of example usage call: Wait until a byte has been received, then return that byte.
176 | }}
177 |
178 | repeat while (rxByte := RxCheck) < 0 'return the byte, wait while the buffer is empty
179 |
180 |
181 | PUB Tx(txByte)
182 | {{
183 | Places a byte into the transmit buffer for transmission (may wait for room in buffer).
184 |
185 | Parameters: txByte = the byte to be transmitted
186 | return: none
187 |
188 | example usage: serial.Tx($0D)
189 |
190 | expected outcome of example usage call: Transmits the byte $0D serially on the txPin
191 | }}
192 |
193 | repeat until (tx_tail <> (tx_head + 1) & $F) 'wait until the buffer has room
194 | tx_buffer[tx_head] := txByte 'place the byte into the buffer
195 | tx_head := (tx_head + 1) & $F 'advance the buffer's pointer
196 |
197 | if rxtx_mode & %1000 'if ignoring rx echo
198 | Rx ' receive the echoed byte and discard
199 |
200 |
201 | PUB Str(stringPtr)
202 | {{
203 | Transmit a string of bytes
204 |
205 | Parameters: stringPtr = the pointer address of the null-terminated string to be sent
206 | return: none
207 |
208 | example usage: serial.Str(@test_string)
209 |
210 | expected outcome of example usage call: Transmits each byte of a string at the address some_string.
211 | }}
212 |
213 | repeat strsize(stringPtr)
214 | Tx(byte[stringPtr++]) 'Transmit each byte in the string
215 |
216 |
217 | PUB Dec(value) | i, x
218 | {{
219 | Transmit the ASCII string equivalent of a decimal value
220 |
221 | Parameters: dec = the numeric value to be transmitted
222 | return: none
223 |
224 | example usage: serial.Dec(-1_234_567_890)
225 |
226 | expected outcome of example usage call: Will print the string "-1234567890" to a listening terminal.
227 | }}
228 |
229 | x := value == NEGX 'Check for max negative
230 | if value < 0
231 | value := ||(value+x) 'If negative, make positive; adjust for max negative
232 | Tx("-") 'and output sign
233 |
234 | i := 1_000_000_000 'Initialize divisor
235 |
236 | repeat 10 'Loop for 10 digits
237 | if value => i
238 | Tx(value / i + "0" + x*(i == 1)) 'If non-zero digit, output digit; adjust for max negative
239 | value //= i 'and digit from value
240 | result~~ 'flag non-zero found
241 | elseif result or i == 1
242 | Tx("0") 'If zero digit (or only digit) output it
243 | i /= 10 'Update divisor
244 |
245 |
246 | PUB Hex(value, digits)
247 | {{
248 | Transmit the ASCII string equivalent of a hexadecimal number
249 |
250 | Parameters: value = the numeric hex value to be transmitted
251 | digits = the number of hex digits to print
252 | return: none
253 |
254 | example usage: serial.Hex($AA_FF_43_21, 8)
255 |
256 | expected outcome of example usage call: Will print the string "AAFF4321" to a listening terminal.
257 | }}
258 |
259 | value <<= (8 - digits) << 2
260 | repeat digits 'do it for the number of hex digits being transmitted
261 | Tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))' Transmit the ASCII value of the hex characters
262 |
263 |
264 | PUB Bin(value, digits)
265 | {{
266 | Transmit the ASCII string equivalent of a binary number
267 |
268 | Parameters: value = the numeric binary value to be transmitted
269 | digits = the number of binary digits to print
270 | return: none
271 |
272 | example usage: serial.Bin(%1110_0011_0000_1100_1111_1010_0101_1111, 32)
273 |
274 | expected outcome of example usage call: Will print the string "11100011000011001111101001011111" to a listening terminal.
275 | }}
276 |
277 | value <<= 32 - digits
278 | repeat digits
279 | Tx((value <-= 1) & 1 + "0") 'Transmit the ASCII value of each binary digit
280 |
281 |
282 | DAT
283 |
284 | '***********************************
285 | '* Assembly language serial driver *
286 | '***********************************
287 |
288 | org
289 | '
290 | '
291 | ' Entry
292 | '
293 | entry mov t1,par 'get structure address
294 | add t1,#4 << 2 'skip past heads and tails
295 |
296 | rdlong t2,t1 'get rx_pin
297 | mov rxmask,#1
298 | shl rxmask,t2
299 |
300 | add t1,#4 'get tx_pin
301 | rdlong t2,t1
302 | mov txmask,#1
303 | shl txmask,t2
304 |
305 | add t1,#4 'get rxtx_mode
306 | rdlong rxtxmode,t1
307 |
308 | add t1,#4 'get bit_ticks
309 | rdlong bitticks,t1
310 |
311 | add t1,#4 'get buffer_ptr
312 | rdlong rxbuff,t1
313 | mov txbuff,rxbuff
314 | add txbuff,#16
315 |
316 | test rxtxmode,#%100 wz 'init tx pin according to mode
317 | test rxtxmode,#%010 wc
318 | if_z_ne_c or outa,txmask
319 | if_z or dira,txmask
320 |
321 | mov txcode,#transmit 'initialize ping-pong multitasking
322 | '
323 | '
324 | ' Receive
325 | '
326 | receive jmpret rxcode,txcode 'run a chunk of transmit code, then return
327 |
328 | test rxtxmode,#%001 wz 'wait for start bit on rx pin
329 | test rxmask,ina wc
330 | if_z_eq_c jmp #receive
331 |
332 | mov rxbits,#9 'ready to receive byte
333 | mov rxcnt,bitticks
334 | shr rxcnt,#1
335 | add rxcnt,cnt
336 |
337 | :bit add rxcnt,bitticks 'ready next bit period
338 |
339 | :wait jmpret rxcode,txcode 'run a chuck of transmit code, then return
340 |
341 | mov t1,rxcnt 'check if bit receive period done
342 | sub t1,cnt
343 | cmps t1,#0 wc
344 | if_nc jmp #:wait
345 |
346 | test rxmask,ina wc 'receive bit on rx pin
347 | rcr rxdata,#1
348 | djnz rxbits,#:bit
349 |
350 | shr rxdata,#32-9 'justify and trim received byte
351 | and rxdata,#$FF
352 | test rxtxmode,#%001 wz 'if rx inverted, invert byte
353 | if_nz xor rxdata,#$FF
354 |
355 | rdlong t2,par 'save received byte and inc head
356 | add t2,rxbuff
357 | wrbyte rxdata,t2
358 | sub t2,rxbuff
359 | add t2,#1
360 | and t2,#$0F
361 | wrlong t2,par
362 |
363 | jmp #receive 'byte done, receive next byte
364 | '
365 | '
366 | ' Transmit
367 | '
368 | transmit jmpret txcode,rxcode 'run a chunk of receive code, then return
369 |
370 | mov t1,par 'check for head <> tail
371 | add t1,#2 << 2
372 | rdlong t2,t1
373 | add t1,#1 << 2
374 | rdlong t3,t1
375 | cmp t2,t3 wz
376 | if_z jmp #transmit
377 |
378 | add t3,txbuff 'get byte and inc tail
379 | rdbyte txdata,t3
380 | sub t3,txbuff
381 | add t3,#1
382 | and t3,#$0F
383 | wrlong t3,t1
384 |
385 | or txdata,#$100 'ready byte to transmit
386 | shl txdata,#2
387 | or txdata,#1
388 | mov txbits,#11
389 | mov txcnt,cnt
390 |
391 | :bit test rxtxmode,#%100 wz 'output bit on tx pin according to mode
392 | test rxtxmode,#%010 wc
393 | if_z_and_c xor txdata,#1
394 | shr txdata,#1 wc
395 | if_z muxc outa,txmask
396 | if_nz muxnc dira,txmask
397 | add txcnt,bitticks 'ready next cnt
398 |
399 | :wait jmpret txcode,rxcode 'run a chunk of receive code, then return
400 |
401 | mov t1,txcnt 'check if bit transmit period done
402 | sub t1,cnt
403 | cmps t1,#0 wc
404 | if_nc jmp #:wait
405 |
406 | djnz txbits,#:bit 'another bit to transmit?
407 |
408 | jmp #transmit 'byte done, transmit next byte
409 | '
410 | '
411 | ' Uninitialized data
412 | '
413 | t1 res 1
414 | t2 res 1
415 | t3 res 1
416 |
417 | rxtxmode res 1
418 | bitticks res 1
419 |
420 | rxmask res 1
421 | rxbuff res 1
422 | rxdata res 1
423 | rxbits res 1
424 | rxcnt res 1
425 | rxcode res 1
426 |
427 | txmask res 1
428 | txbuff res 1
429 | txdata res 1
430 | txbits res 1
431 | txcnt res 1
432 | txcode res 1
433 |
434 |
435 | DAT
436 | {{
437 | ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
438 | │ TERMS OF USE: MIT License │
439 | ├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
440 | │Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
441 | │files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
442 | │modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
443 | │is furnished to do so, subject to the following conditions: │
444 | │ │
445 | │The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
446 | │ │
447 | │THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
448 | │WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
449 | │COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
450 | │ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
451 | └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
452 | }}
--------------------------------------------------------------------------------
/software/sidplay/src/SIDcogSlave/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | openspin SIDcogSlave.spin
3 | upload:
4 | p1load -r SIDcogSlave.binary
5 | eeprom:
6 | p1load -e -r SIDcogSlave.binary
7 |
--------------------------------------------------------------------------------
/software/sidplay/src/SIDcogSlave/SIDcog.spin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/software/sidplay/src/SIDcogSlave/SIDcog.spin
--------------------------------------------------------------------------------
/software/sidplay/src/SIDcogSlave/SIDcogSlave.spin:
--------------------------------------------------------------------------------
1 | CON
2 | _CLKMODE = xtal1 + pll16x
3 | _XINFREQ = 6_000_000
4 |
5 | OBJ
6 | sid : "SIDcog"
7 | serial : "FullDuplexSerial"
8 |
9 | VAR
10 | byte registers[25]
11 |
12 | PUB main | readyToUpdateRegisters, i
13 |
14 | sid.start( 0, 1 )
15 | serial.start( 31, 30, 0, 115200 )
16 |
17 | dira[1..9] := %11111111
18 | outa[1..9] := %11111111
19 |
20 | repeat
21 | readyToUpdateRegisters := false
22 | repeat while not readyToUpdateRegisters
23 | repeat while serial.rx <> 13
24 | if serial.rx == "S" and serial.rx == "D" and serial.rx == "M" and serial.rx == "P"
25 | readyToUpdateRegisters := true
26 | repeat i from 0 to 24
27 | registers[i] := serial.rx
28 | repeat i from 0 to 7
29 | outa[i+2] := registers[i] & 1
30 | sid.updateRegisters( @registers )
31 |
--------------------------------------------------------------------------------
/software/sidplay/src/sidplay/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | gcc -c -g -O3 sidplay.c -Wall -Winline -pipe -I/usr/local/lib
3 | gcc -o sidplay sidplay.o -lwiringPi -lpthread -lm -L/usr/local/lib
4 |
--------------------------------------------------------------------------------
/software/sidplay/src/sidplay/sidplay.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 | #include
9 |
10 | #include
11 | #include
12 |
13 | int fd;
14 | FILE* fp;
15 | int i;
16 | long start_time;
17 | int duration;
18 |
19 | void cleanup(void){
20 | serialPrintf(fd, "%cSDMP", 13);
21 | for(i = 0; i < 25; i++){
22 | serialPutchar(fd,0);
23 | }
24 | fclose(fp);
25 | serialClose(fd);
26 | }
27 |
28 | void sigintHandler(int sig_num){
29 | cleanup();
30 | exit(1);
31 | }
32 |
33 | long getTime(){
34 | time_t seconds;
35 | seconds = time(NULL);
36 | return (long)seconds;
37 | }
38 |
39 | int main( int argc, char *argv[] ){
40 |
41 | int playrate = 1000.0/50.0;
42 |
43 | fprintf(stdout,"SIDcog Serial Player\n");
44 | fflush(stdout);
45 |
46 | if( argc < 2 ){
47 | fprintf(stdout, "Usage: %s \n", argv[0]);
48 | return 1;
49 | }
50 |
51 | if( argc > 2 ){
52 | float rate = atof(argv[2]);
53 | if(rate > 460){
54 | fprintf(stdout, "Warning, max play rate is 460 updates/sec\n");
55 | rate = 460;
56 | }
57 | playrate = 1000.0 / rate;
58 | }
59 |
60 | duration = 0;
61 | if( argc > 3){
62 | duration = atoi(argv[3]);
63 | }
64 |
65 | fp = fopen(argv[1], "rb");
66 |
67 | fd = serialOpen("/dev/ttyAMA0",115200);
68 |
69 | fprintf(stdout,"Serial Opened\n");
70 | fflush(stdout);
71 |
72 | char buf[26];
73 |
74 | signal(SIGINT, sigintHandler);
75 |
76 | start_time = getTime();
77 |
78 | while(fread(buf, 1, 25, fp) == 25){
79 | /*
80 | Send the header for the beginning of
81 | each register packet.
82 |
83 | chr(13) + S + D + M + P
84 | */
85 | serialPrintf(fd, "%cSDMP", 13);
86 | /*
87 | Must send the buffer one char at a time
88 | since zeros will get interpreted as
89 | the termination string in Printf
90 | */
91 | for(i = 0; i < 26; i++){
92 | serialPutchar(fd,buf[i]);
93 | }
94 | delay(playrate);
95 |
96 | if(duration > 0 && start_time + duration <= getTime()){
97 | break;
98 | }
99 | }
100 |
101 | cleanup();
102 |
103 | return 0;
104 | }
105 |
--------------------------------------------------------------------------------
/terminal.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pimoroni/propeller-hat/203d1e64f05a6bf43f75313bdce60d4a892c30d1/terminal.jpg
--------------------------------------------------------------------------------