├── .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 | ![Propeller HAT](propeller-hat.jpg) 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 | ![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) 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 | ![Finding the terminal](terminal.jpg) 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 | ![Propeller IDE download](propeller-ide-download.png) 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 | ![Propeller HUB and Cog Diagram](images/propeller-hub-cog-diagram.png) 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 | ![Propeller Multicore Layout](images/layout-diving-into-multicore.png) 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 | ![Propeller Blink Layout](images/layout-your-first-spin.png) 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 | ![Propeller IDE download](images/propeller-ide-download.png) 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 | ![Raspberry Pi, disable Serial Terminal](images/propeller-ide-serial-terminal.png) 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 | ![I can SPIN a rainbow!](images/i-can-spin-a-rainbow.png) 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 | ![Propeller Multicore Layout](images/layout-your-first-spin.png) 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 | ![CC BY-SA 4.0](https://i.creativecommons.org/l/by-sa/4.0/88x31.png) 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 --------------------------------------------------------------------------------