Skip to content
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

rebase _index.md PR #320 #345

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
6 changes: 6 additions & 0 deletions content/docs/concepts/peripherals/i2c.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ You could think of this auto-increment behavior as reading a file. Step 1 opens

Writing is very similar. The main difference is that the controller writes data to the peripheral instead of starting to read bytes after the initial register number is written to the peripheral.

## Target mode

Typically, I2C peripherals are used in controller mode to communicate with sensors and other devices. In I2C target mode, the peripheral instead takes the role of the target (i.e. the role of a sensor/similar device). In this case, the application logic is responsible for processing and responding to messages initiated by an I2C controller, according to this flow diagram:

![I2C Target Flow](/images/i2c-target-flow.png)

## Interacting with a device

For this example, we'll use the [MPU6050](https://invensense.tdk.com/products/motion-tracking/6-axis/mpu-6050/) which is a very common (but old) sensor that measures acceleration and rotation. We won't be doing much interesting with it, but it serves as a great introduction into how to work with I2C peripherals with TinyGo.
Expand Down
9 changes: 8 additions & 1 deletion content/docs/guides/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,16 +172,23 @@ You have successfully built TinyGo from source. Congratulations!

We're not done yet. Some extra things need to be built before you can start using TinyGo.

If you haven't already, you need to download llvm-project (for the compiler-rt sources that are needed for most architectures):

```shell
make llvm-source
```

To be able to use TinyGo on a bare-metal target, you need to generate some files first:

```shell
make gen-device
```

To be able to use TinyGo to build WebAssembly binaries, you will need to compile [wasi-libc](https://github.com/WebAssembly/wasi-libc):
To be able to use TinyGo to build WebAssembly binaries, you will need to compile [wasi-libc](https://github.com/WebAssembly/wasi-libc) and [Binaryen](https://github.com/WebAssembly/binaryen):

```shell
make wasi-libc
make binaryen
```

These command may need to be re-run after some updates in TinyGo.
Expand Down
1 change: 1 addition & 0 deletions content/docs/guides/contributing/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Here is how to contribute back some code or documentation:
- Fork repo
- Create a feature branch off of the `dev` branch
- Make some useful change
- Format the change using `make fmt`
- Make sure the tests still pass
- Submit a pull request against the `dev` branch.
- Be kind
Expand Down
103 changes: 101 additions & 2 deletions content/docs/reference/machine.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,21 +84,89 @@ SetInterrupt sets an interrupt to be executed when the pin changes state. The pi
This call will replace a previously set callback on this pin. You can pass `nil` to disable the interrupt. If you do so, the change parameter is ignored and can be set to any value (such as 0).


## SPI

```go
type SPIConfig struct {
Frequency uint32
SCK Pin
SDO Pin
SDI Pin
LSBFirst bool
Mode uint8
}
```

The `SPIConfig` struct contains the configuration for the SPI peripheral.

* `Frequency` is the maximum frequency that will be used: for example `1 * MHz` for 1MHz. Depending on chip capabilities, this or a lower frequency will be selected. When not set (or set to 0), the default of 4MHz will be used.
* `SCK`, `SDO` and `SDI` are the clock, data out, and data in pins respectively, however support for setting pins other than the default pins may not be supported by a given SPI peripheral. Some chips are flexible and allow the use of any pin, while other boards only allow a limited range of pins or use fixed SCK/SDO/SDI pins. When these pins are left at the zero value, the default for the particular board is used.
* `LSBFirst` configures the SPI peripheral to clock out the least significant bit (LSB) first. The default and most commonly used configuration is the most significant bit first (`LSBFirst=false`).
* `Mode` is the [SPI mode (CPOL/CPHA) to be used](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface#Clock_polarity_and_phase). Mode 0 is appropriate for most peripheral chips, but other modes may be needed in some cases. Check your peripheral documentation for details.
| Mode | CPOL | CPHA |
| ------- | ---- | ---- |
| `Mode0` | 0 | 0 |
| `Mode1` | 0 | 1 |
| `Mode2` | 1 | 0 |
| `Mode3` | 1 | 1 |

```go
type SPI struct {
// values are unexported or vary by chip
}

var (
SPI0 = SPI{...}
SPI1 = SPI{...}
)
```

The `SPI` object refers to a single (hardware) SPI instance. Depending on chip capabilities, various objects such as `SPI0` and perhaps others are defined.

```go
func (spi SPI) Configure(config SPIConfig) error
```

The `Configure` call enables and configures the hardware SPI for use, setting the configuration as described in `SPIConfig`. It will return an error when an incorrect configuration is provided (for example, using pins not usable with this SPI instance). See `SPIConfig` for details.

```go
func (spi SPI) Transfer(b byte) (byte, error)
```

Transmit and receive a single byte. Due to the nature of the SPI protocol, they happen both at the same time.

Use `Tx` instead of `Transfer` for high performance bulk transfers.

```go
func (spi SPI) Tx(w, r []byte) error
```

The `Tx` performs the actual SPI transaction, and return an error if there was an error during the transaction. Because SPI is a synchronous protocol, reading and writing happens at the same time. Therefore, `w` and `r` usually have to be the same length. There are some exceptions:

* When `r` is nil, the SPI peripheral will only transmit the bytes in `w` and ignore what it receives.
* When `w` is nil, the SPI peripheral will only read the given number of bytes and store it in `r`. It will send out a zero byte for each byte that it reads.

Some chips may also support mismatched lengths of `w` and `r`, in which case they will behave like above for the remaining bytes in the byte slice that's the longest of the two.


## I2C

```go
type I2CConfig struct {
Frequency uint32
SCL Pin
SDA Pin
Mode I2CMode
}
```

The `I2CConfig` struct contains the configuration for the I2C peripheral.

* `Frequency` can be set to either 100kHz (`100e3`), 400kHz (`400e3`), and sometimes to other values depending on the chip. The zero value defaults to 100kHz.
* `SCL` and `SDA` can be set as desired, however support for different pins than the default is limited. Some chips are flexible and allow the use of any pin, while other boards only allow a limited range of pins or use fixed SCL/SDA pins. When both pins are left at the zero value, the default for the particular board is used.

* `Mode` is present on peripherals that support I2C target mode. The default
is I2C controller mode, setting `Mode` to `I2CModeTarget` will configure the
peripheral as an I2C target.
```go
type I2C struct {
// values are unexported or vary by chip
Expand All @@ -122,8 +190,39 @@ The `Configure` call enables and configures the hardware I2C for use, setting th
func (i2c I2C) Tx(addr uint16, w, r []byte) error
```

The `Tx` call performs the actual I2C transaction. It first writes the bytes in `w` to the peripheral device indicated in `addr` and then reads `r` bytes from the peripheral and stores the read bytes in the `r` slice. It returns an error if the transaction failed. Both `w` and `r` can be `nil`.
_I2C Controller Mode Only_: The `Tx` call performs the actual I2C transaction. It first writes the bytes in `w` to the peripheral device indicated in `addr` and then reads `r` bytes from the peripheral and stores the read bytes in the `r` slice. It returns an error if the transaction failed. Both `w` and `r` can be `nil`.

```go
func (i2c I2C) Listen(addr uint16) error
```

_I2C Target Mode Only_: The `Listen` call starts the I2C peripheral listening for I2C transactions sent
to `addr` by the controller. The peripheral must have been configured in target
mode (see `I2CConfig` struct) before `Listen` is called.

```go
func (i2c *I2C) WaitForEvent(buf []byte) (evt I2CTargetEvent, count int, err error)
```

_I2C Target Mode Only_: The `WaitForEvent` call blocks the current goroutine waiting for an I2C event. For `I2CReceive` events, the message will be placed in `buf` and return the `count` of bytes received. Oversize messages (those larger than `buf`) will be truncated.

The underlying peripheral will perform clock stretching, if necessary, in two cases:

1. A correctly addressed message is received and the application is not blocked on a call to `WaitForEvent`,

2. The application does not call `Reply` with a single I2C clock cycle for `I2CRequest` events.

Although the I2C target may perform clock stretching, controllers may implement arbitrary timeouts for pending devices. To avoid timeouts from the perspective a controller, the application should:

1. Handle the returned event in a timely manner, calling `Reply` if appropriate.

2. Not have any go routines that may block indefinitely as `WaitForEvent` may yield the CPU to another go routine while waiting for an event.

```go
func (i2c I2C) Reply(buf []byte) error
```

_I2C Target Mode Only_: The `Reply` call sends a response to the controller when an `I2CRequest` event is received by the target.

## UART

Expand Down
53 changes: 52 additions & 1 deletion content/docs/reference/usage/subcommands.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,58 @@ Compile and link the program into a regular executable. For microcontrollers, it
Run the program, either directly on the host or in an emulated environment (depending on `-target`).

### flash
Flash the program to a microcontroller.
Flash the program to a microcontroller. Some common flags are described below.

`-target={name}`: Specifies the type of microcontroller that is used. The `name`
of the microcontroller is given on the individual pages for each board type
listed under [Microcontrollers]({{<ref "../microcontrollers/">}}). For example,
`arduino-nano`, `d1mini`, `xiao`.

`-monitor`: Start the serial monitor (see below) immediately after flashing.
However, some microcontrollers need a split second or two to configure the
serial port after flashing, and using the `-monitor` flag can fail because the
serial monitor starts too quickly. In that case, use the `tinygo monitor`
command explicitly.

### monitor
Start the serial monitor on the serial port that is connected to the
microcontroller. If there is only a single board attached to the host computer,
the default values for various options should be sufficient. In other
situations, particularly if you have multiple microcontrollers attached, some
parameters may need to be overridden using the following flags:

`-port={port}`: If there are multiple microcontroller attached, an error message
will display a list of potential serial ports. The appropriate port can be
specified by this flag. On Linux, the port will be something like `/dev/ttyUSB0`
or `/dev/ttyACM1`. On MacOS, the port will look like `/dev/cu.usbserial-1420`.
On Windows, the port will be something like `COM1` or `COM31`.

`-baudrate={rate}`: The default baud rate is 115200. Boards using the AVR
processor (e.g. [Arduino Nano]({{<ref "../microcontrollers/arduino-nano.md">}}),
[Arduino Mega 2560]({{<ref "../microcontrollers/arduino-mega2560">}})) use 9600
instead.

`-target={name}`: If you have more than one microcontrollers attached, you can
sometimes just specify the target name and let `tinygo monitor` figure out the
port. Sometimes, this does not work and you have to explicitly use the `-port`
flag.

The serial monitor intercepts several control characters for its own use instead
of sending them to the microcontroller:

* Control-C: terminates the `tinygo monitor`
* Control-Z: suspends the `tinygo monitor` and drops back into shell
* Control-\\: terminates the `tinygo monitor` with a stack trace
* Control-S: flow control, suspends output to the console
* Control-Q: flow control, resumes output to the console
* Control-@: thrown away by `tinygo monitor`

**Note**: If you are using `os.Stdin` on the microcontroller, you may find that
a CR character on the host computer (also known as Enter, `^M`, or `\r`) is
transmitted to the microcontroller without conversion, so `os.Stdin` returns a
`\r` character instead of the expected `\n` (also known as `^J`, NL, or LF) to
indicate end-of-line. You may be able to get around this problem by hitting
`Control-J` in `tinygo monitor` to transmit the `\n` end-of-line character.

### gdb
Compile the program, optionally flash it to a microcontroller if it is a remote target, and drop into a GDB shell. From there you can set breakpoints, start the program with `run` or `continue` (`run` for a local program, `continue` for on-chip debugging), single-step, show a backtrace, break and resume the program with Ctrl-C/`continue`, etc. You may need to install extra tools (like `openocd` and `arm-none-eabi-gdb`) to be able to do this. Also, you may need a dedicated debugger to be able to debug certain boards if no debugger is integrated. Some boards (like the BBC micro:bit and most professional evaluation boards) have an integrated debugger.
Expand Down
Loading