Skip to content

Add Impeeduino Library #44

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
3718cf1
Initial commit of abstraction class
Nov 3, 2016
94481c7
First draft of digitalRead, correct sequencing but incorrect values
Nov 3, 2016
0ba4696
Update README.md
AG6GR Nov 3, 2016
6e0004a
Fixed digitalRead(), still strangeness with Arduino input pin not pul…
Nov 4, 2016
e815a11
Add notes on communication format between Imp and Arduino. Change arb…
Nov 5, 2016
f8a5b9c
Edit analog ops descriptions, drew out corresponding arb data bytes
Nov 5, 2016
67e6163
Implement analogRead and analogWrite
Nov 6, 2016
a3ccc29
Fix analogWrite to properly wait for data bytes
Nov 6, 2016
aa75e0b
Remap PWM pins to fit within address space
Nov 6, 2016
4fa8770
Add web control example
Nov 6, 2016
5820b12
Implement analogWrite in Imp code
Nov 6, 2016
243280c
Implement callbacks, digitalRead working, rest not so much
Nov 6, 2016
a26655e
Fix analogRead callback's parameter type
Nov 6, 2016
75ee433
Working function calls!
Nov 6, 2016
686fa91
Update remote control demo to include async calls
Nov 6, 2016
0af5ac4
Separate library and programmer documentation
Nov 6, 2016
e6c4ee5
Lay out structure of library README
Nov 6, 2016
3df62f0
Refactor library for style
Nov 6, 2016
2060d76
Update README, Add support for float analogWrite values
Nov 6, 2016
5aeda0f
Add MIT License
Nov 6, 2016
84b21fb
Update introduction, add License
Nov 6, 2016
7430441
Update README.md
AG6GR Nov 6, 2016
68c6ebd
Rename programmer source files
Nov 6, 2016
0989cf1
Update README.md
AG6GR Nov 6, 2016
f7a0c71
Start on function call demo
Nov 7, 2016
276b440
Add version check
Nov 7, 2016
8a49f89
Disable debug server.log() calls
Nov 7, 2016
c457d44
Update comments
Nov 7, 2016
980ecfd
Fixed small typo
Nov 7, 2016
f81463b
Update LICENSE to correct copyright year
AG6GR Nov 7, 2016
1bd9ee7
Update README.md
AG6GR Nov 7, 2016
0088275
Remove extraneous device code from library squirrel file. Advance ver…
Nov 7, 2016
163aba7
Merge branch 'master' of github.com:AG6GR/reference
Nov 7, 2016
eeb5da3
Update license headers
Nov 7, 2016
679bc6b
Fresh version of Arduino code
Apr 2, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2013 Electric Imp
Copyright (c) 2016 Electric Imp

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
1 change: 1 addition & 0 deletions hardware/impeeduino/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*~
21 changes: 21 additions & 0 deletions hardware/impeeduino/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2016 Electric Imp

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
171 changes: 151 additions & 20 deletions hardware/impeeduino/README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,163 @@
Impeedunio Programmer
=====================
# Impeeduino 1.0.0

This firmware will allow you to program the ATmega328 built into the Impduino.
It parses Intel HEX files delivered via HTTP POST (form) and implements the STK500v1 serial protocol to talk to the connected ATmega328.
The Impeeduino is a combination of an imp001 and an Arduino. This library provides a simple way to instruct the Arduino side of the Impeeduino to perform basic tasks over UART.

You will need to install the "[optiboot](https://code.google.com/p/optiboot/)" bootloader using an ICSP cable. At the time of writing, the latest version was [v5.0a](https://code.google.com/p/optiboot/downloads/detail?name=optiboot-v5.0a.zip).
To do this you will need an ISP or use [another Ardiuno as the ISP](http://arduino.cc/en/Tutorial/ArduinoISP) and the ArduinoISP sketch.
The Impeeduino squirrel library contained in `impeeduino.class.nut` pairs with the [impeeduino Arduino project](./arduino/impeeduino). More details on the underlying UART communication scheme and instructions on taking advantage of the user-modifiable function call system can be found in the corresponding [Readme file](./arduino/impeeduino/README.md).

You might need to adjust the signature of the ATmega328P in the avrdude configuration to make avrdude think its an ATmega328P.
/Applications/Arduino.app/Contents/Resources/Java/hardware/tools/avr/etc/avrdude.conf
To upload Arduino code onto the Impeeduino's ATmega328, an [Impeeduino Programmer model](./programmer) is provided. This model includes agent and device code for programming the Arduino via an Imp with a HEX file generated from the Arduino IDE.

From: signature = 0x1e 0x95 0x0f;
To: signature = 0x1e 0x95 0x14;
<!--
**To add this library to your project, add** `#require "Impeeduino.nut:1.0.0"` **to the top of your device code.**
-->

Once the ATMega is programmed you can continue to talk to it over the serial port.
## Class Usage

Note, if you are using the [SparkFun Imp Shield](https://www.sparkfun.com/products/11401) then you may need to reverse the
logic of the RESET pin. Where you see RESET.write(1), change it to RESET.write(0) and vice versa.
### Constructor: Impeeduino(*[serial, reset]*)

The constructor takes two arguments to instantiate the class: a non-configured UART bus and a GPIO pin connected to the Arduino's reset line. These default to the configuration used on the Impeeduino rev2, using `uart57` for serial communications and `pin1` for the reset line.

Contributors
============
```squirrel
impeeduino <- Impeeduino();

- Aron
// Equivalent, but more verbose instantiation:
impeeduino <- Impeeduino(hardware.uart57, hardware.pin1);
```

Usage
=====
## Class Methods

This is not a library class. It represents an entire application for programming the Arduino via an Imp with a HEX file.
You can adapt it to your needs, such as combining the programming functionality with application level communication.
### reset()

Resets the ATMega processor by bouncing the reset pin. Note that reseting will block the imp for about 0.2 seconds.

```squirrel
impeeduino.reset();
```

### pinMode(*pin, mode*)

Configures the specified GPIO pin to the specified mode. Possible configurations are input, input with pullup, output, and PWM output. The relevant constants are summarized below. Note that not all ATMega pins are capable of being used for PWM output.

| Mode Constant | Configuration |
| ------------- | ------------- |
| DIGITAL_IN | Input (High Impedance) |
| DIGITAL_IN_PULLUP | Input with pullup |
| DIGITAL_OUT | Digital output |
| PWM_OUT | PWM output |


```squirrel
// Configure pin 2 as digital input
impeeduino.pinMode(2, DIGITAL_IN);

// Configure pin 3 as digital input with pullup
impeeduino.pinMode(3, DIGITAL_IN_PULLUP);

// Configure pin 4 as digital output
impeeduino.pinMode(4, DIGITAL_OUT);

// Configure pin 5 as PWM output
impeeduino.pinMode(5, PWM_OUT);
```

### digitalWrite(*pin, value*)

Writes a value to the specified digital pin. Value can be either a boolean or an integer value. For boolean values, true corresponding to high and false to low. For integers, non-zero values correspond to high and zero corresponds to false.

```squirrel
// Set pin 4 to HIGH
digitalWrite(4, 1);

// Set pin 4 to LOW
digitalWrite(4, 0);

// Toggle pin 4 every 2 seconds
isOn <- true;

function blink() {
digitalWrite(4, isOn);
isOn = !isOn;
imp.wakeup(2, blink);
}

blink();
```

### analogWrite(*pin, value*)

Writes an analog value (PWM wave) to a pin. *value* is an integer value representing the duty cycle and ranges between 0 (off) and 255 (always on). For compatibility with imp code, value may also be a floating point duty ratio from 0.0 to 1.0. This is then rounded to the nearest available value.

```squirrel
// Configure pin 5 as pwm output
impeeduino.pinMode(5, PWM_OUT);

// Set pin 5 to 50% duty cycle
impeeduino.analogWrite(5, 0.5);

// Set pin 5 to 0% duty cycle (always off)
impeeduino.analogWrite(5, 0);

// Set pin 5 to 100% duty cycle (always on)
impeeduino.analogWrite(5, 255);
```

### digitalRead(*pin[, callback]*)

Reads the logical value of the specified digital pin and returns it as an integer. A value of 0 corresponds to digital low, a value of 1 corresponds to digital high.

If a callback parameter is provided, the reading executes asynchronously and the resulting integer value will be passed to the supplied function as the only parameter. If no callback is provided, the method blocks until the reading has been taken.

#### Asynchronous Example

```squirrel
// Read pin 2 asynchronously and log the returned value
impeeduino.digitalRead(2, function(value) {
server.log("Async digital read: Pin 2 has value " + value);
});
```

#### Synchronous Example

```squirrel
// Read pin 2 and log the returned value
server.log("Digital read: Pin 2 has value " + impeeduino.digitalRead(2));
```

### analogRead(*pin[, callback]*)

Reads the value of the specified analog pin and returns it as an integer. The Arduino has a 10-bit ADC, so returned values will range from 0 to 1023.

If a callback parameter is provided, the reading executes asynchronously and the resulting integer value will be passed to the supplied function as the only parameter. If no callback is provided, the method blocks until the reading has been taken.

#### Asynchronous Example

```squirrel
// Read analog pin 0 asynchronously and log the returned value
impeeduino.analogRead(0, function(value) {
server.log("Async analog read: Pin A0 has value " + value);
});
```

#### Synchronous Example

```squirrel
// Read analog pin 0 and log the returned value
server.log("Analog read: Pin A0 has value " + impeeduino.analogRead(0));
```
### functionCall(*id[, argument, callback]*)

Performs a function call on the Arduino. This is intended as a way to trigger additional functionality on the Arduino. There are 30 user-modifiable custom functions available in the Arduino code, with id numbers 1-30.

Each function may take an ASCII string argument and optionally pass back an ASCII string return value. Because the underlying serial communication scheme uses the most significant bit to indicate commands, only standard ASCII characters (value 0-127) may be sent.

Arduino function calls are asynchronous. The returned string will be passed to as the sole parameter to the optional callback as a binary blob.

```squirrel
server.log("Calling function 1");
impeeduino.functionCall(1, "This is the argument", function(value) {
server.log("Function 1 returned with value: " + value);
});
```

## Licence

The Impeeduino library is provided under the [MIT License](./LICENSE).
81 changes: 81 additions & 0 deletions hardware/impeeduino/arduino/impeeduino/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Impeeduino Communication Scheme
This document provides documentation for the communication scheme between the imp001 and the ATMega. Incoming serial data is interpreted byte by byte, with commands differentiated from regular ASCII data by checking the most significant bit of each byte. This allows us to take advantage of regular strings sent via Serial.print() on the Arduino as a simple way to pass data while still leaving sufficient address space to assign most common functions to concise commands.

## Instruction Format
Instruction format: `1[op (3b)][addr (4b)]`

Any byte received that does not have its MSB set to 1 is interpreted as ASCII data and is added to function call buffer. The next 3 bits (bits 6:4) define the opcode, which determines what operation to perform. The last 4 bits (bits 3:0) define an address, usually used to describe a pin number.

### 000 (0x80): Configure Pin
A command to configure a pin must be followed by arbitrary data op specifying the config type.

Arbitrary data command byte format: `1111[configtype (4b)]`

| Config Type | Decimal | Hex | Binary |
| ----------- | ------- | --- | ------ |
| Input | 0 | 0x0 | 0000 |
| Input Pullup| 1 | 0x1 | 0001 |
| Output | 2 | 0x2 | 0010 |
| PWM Output | 3 | 0x3 | 0011 |

### 001 (0x90): Digital Read
The Arduino responds to a digital read command with digital write command byte corresponding to the read value. For instance, if the Arduino receives `0x96`, instructing a digital read of pin 6, it will respond with `0xA6` (Digital Write 0 on Pin 6) if pin 6 is low or `0xB6` (Digital Write 1 on Pin 6) if pin 6 is high.

### 010 (0xA0): Digital Write 0
Write digital low to the specified pin address.
### 011 (0xB0): Digital Write 1
Write digital high to the specified pin address.

### 100 (0xC0): Analog Op
This opcode represents both analog reads and writes. Since there are only 5 analog inputs and 6 PWM enabled outputs on the Arduino, this first bit of the address field can be used to choose between a analogWrite or analogRead while still being able to address all the applicable pins. In the future it might be worth redesignating one of the function call opcodes in order to address boards with more outputs.

Analog operation format: `1100[W/~R (1b)][addr (3b)]`

For analog writes, the Arduino pin numbers are remapped to the available address space as shown below:

| Arduino Pin Number | Command Address | Example Analog Write |
| -------- | --------- | ----------- |
| 3 | 0 | `0xC8 = 1100 1 000` |
| 5 | 1 | `0xC9 = 1100 1 001` |
| 6 | 2 | `0xCA = 1100 1 010` |
| 9 | 3 | `0xCB = 1100 1 011` |
| 10 | 4 | `0xCC = 1100 1 100` |
| 11 | 5 | `0xCD = 1100 1 101` |

Analog writes must also pass a 1 byte argument for the PWM duty cycle. The two bytes after the intial analogWrite command must be arbitrary data bytes with the least significant word, then most significant word, of the duty cycle.
Thus a complete analogWrite instruction would be: `1100 1[addr (3b)], 1101[LSB (4b)], 1101[MSB (4b)]`.

Analog reads return a 10-bit ADC value. The Arduino responds with a copy of the original analog operation command followed by 3 arbitrary data commands containing the 10-bit ADC value split into 3 words. The words are sent in little-endian order.
A complete analogRead response would be: `1100 0[addr (3b)], 1101 [ADC(3:0)], 1101 [ADC(7:4)], 1101 00[ADC(9:8)]`

### 101 (0xD0): Arbitrary Data
This operation is used by other operations to send words of binary data. It is preferable to have an arbitrary data operation in order to avoid issues with interfering with ASCII data being sent as part of a function call or have awkward situations such as long strings of `0xFF` bytes being confused with a -1 read return value.

### 110 (0xE0) and 111 (0xF0): Call/Return
These operations call user-defined functions in the Arduino code. A character array buffer stores incoming ASCII characters received on the UART bus and is passed as the argument to function calls. Between the opcodes `0xE0` and `0xF0`, there are 32 possible functions that may be called. These are referred to with a 5-bit ID, meaning that it may be more accurate to describe the call operation format as: `11[function id (5b)]`

There are two function calls that are reserved for system use.
- *call 0* (`0xE0` or `11000000`) is used to clear the receive buffers.
- *call 31* (`0xFF` or `11111111`) may not be used to avoid any confusion with -1, which is commonly used to indicate "no data" by UART read functions.

The complete function call process is summarized below:

Valid functions ids are 1-30 (`0x01` to `0x1E`).
function 0 `(0x00)` is reserved as "clear buffer."
function 31 `(0xFF)` is not allowed to avoid confusion with -1.

1. Imp sends *call 0x00* to clear Arduino function buffer
2. Imp sends function argument as ASCII characters (0-127)
3. Arduino places received characters into buffer
4. Imp sends *call 0xXX* to initiate call of the function with id number 0xXX
5. Arduino calls *functionXX()* with the function buffer's contents as the argument
6. *functionXX* returns, optionally with a character array return value
7. Arduino sends *call 0x00* to clear Imp's return value buffer
8. Arduino sends return value as ASCII characters
9. Imp places received characters into buffer
10. Arduino sends *call 0xXX* to indicate function return
11. If a callback has been set, Imp calls it with the returned value as an argument.

## License

The Impeeduino Arduino sketch and associated materials are provided under the [MIT License](../../LICENSE).
Loading