Skip to content

Commit

Permalink
Merge pull request #989 from bettio/i2c-api-renames
Browse files Browse the repository at this point in the history
I2C API renames

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
  • Loading branch information
bettio committed Dec 17, 2023
2 parents 2cc65f7 + 0ec82ff commit eb15ec9
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Shorten SPI config options, such as `sclk_io_num` -> `sclk`
- Shorten I2C config options, such as `scl_io_num` -> `scl`

## [0.6.0-alpha.2] - 2023-12-10

Expand Down
10 changes: 5 additions & 5 deletions doc/src/programmers-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -1159,16 +1159,16 @@ The AtomVM I2C implementation uses the AtomVM Port mechanism and must be initial

| Key | Value Type | Required | Description |
|-----|------------|----------|---|
| `scl_io_num` | `integer()` | yes | I2C clock pin (SCL) |
| `sda_io_num` | `integer()` | yes | I2C data pin (SDA) |
| `i2c_clock_hz` | `integer()` | yes | I2C clock frequency (in hertz) |
| `i2c_num` | `0 .. I2C_NUM_MAX - 1` | no (default: `0`) | I2C port number. `I2C_NUM_MAX` is defined by the device SDK. On ESP32, this value is 1. |
| `scl` | `integer()` | yes | I2C clock pin (SCL) |
| `sda` | `integer()` | yes | I2C data pin (SDA) |
| `clock_speed_hz` | `integer()` | yes | I2C clock frequency (in hertz) |
| `peripheral` | `0 .. I2C_NUM_MAX - 1` | no (default: `0`) | I2C port number. `I2C_NUM_MAX` is defined by the device SDK. On ESP32, this value is 1. |

For example,

%% erlang
I2C = i2c:open([
{scl_io_num, 21}, {sda_io_num, 22}, {i2c_clock_hz, 40000}
{scl, 21}, {sda, 22}, {clock_speed_hz, 40000}
])

Once the port is opened, you can use the returned `I2C` instance to read and write bytes to the attached device.
Expand Down
2 changes: 1 addition & 1 deletion examples/elixir/esp32/SHT31.ex
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ defmodule SHT31 do
@sht31_meas_high_rep 0x2400

def start do
i2c = I2C.open([{:scl_io_num, 15}, {:sda_io_num, 4}, {:i2c_clock_hz, 1000000}])
i2c = I2C.open([{:scl, 15}, {:sda, 4}, {:clock_speed_hz, 1000000}])
loop(i2c)
end

Expand Down
2 changes: 1 addition & 1 deletion examples/erlang/esp32/sht31.erl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
-define(SHT31_MEAS_HIGH_REP, 16#2400).

start() ->
I2C = i2c:open([{scl_io_num, 15}, {sda_io_num, 4}, {i2c_clock_hz, 1000000}]),
I2C = i2c:open([{scl, 15}, {sda, 4}, {clock_speed_hz, 1000000}]),
loop(I2C).

loop(I2C) ->
Expand Down
25 changes: 23 additions & 2 deletions libs/eavmlib/src/i2c.erl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@

-type pin() :: non_neg_integer().
-type freq_hz() :: non_neg_integer().
-type param() :: {scl_io_num, pin()} | {sda_io_num, pin()} | {i2c_clock_hz, freq_hz()}.
-type param() :: {scl, pin()} | {sda, pin()} | {clock_speed_hz, freq_hz()}.
-type params() :: [param()].
-type i2c() :: pid().
-type address() :: non_neg_integer().
Expand All @@ -60,7 +60,7 @@
%%-----------------------------------------------------------------------------
-spec open(Param :: params()) -> i2c().
open(Param) ->
open_port({spawn, "i2c"}, Param).
open_port({spawn, "i2c"}, migrate_config(Param)).

%%-----------------------------------------------------------------------------
%% @param I2C I2C instance created via `open/1'
Expand Down Expand Up @@ -200,3 +200,24 @@ write_bytes(I2C, Address, BinOrInt) ->
) -> ok | {error, Reason :: term()}.
write_bytes(I2C, Address, Register, BinOrInt) ->
port:call(I2C, {write_bytes, Address, BinOrInt, Register}).

migrate_config([]) ->
[];
migrate_config([{K, V} | T]) ->
NewK = rename_key(K),
warn_deprecated(K, NewK),
[{NewK, V} | migrate_config(T)].

rename_key(Key) ->
case Key of
scl_io_num -> scl;
sda_io_num -> sda;
i2c_clock_hz -> clock_speed_hz;
i2c_num -> peripheral;
Any -> Any
end.

warn_deprecated(Key, Key) ->
ok;
warn_deprecated(OldKey, NewKey) ->
io:format("I2C: found deprecated ~p, use ~p instead!!!~n", [OldKey, NewKey]).
8 changes: 4 additions & 4 deletions libs/exavmlib/lib/I2C.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ defmodule I2C do
Used to set the SCL pin, SDA pin, and clock speed.
"""
@type param() ::
{:scl_io_num, gpio_pin()}
| {:sda_io_num, gpio_pin()}
| {:i2c_clock_hz, freq_hz()}
{:scl, gpio_pin()}
| {:sda, gpio_pin()}
| {:clock_speed_hz, freq_hz()}

@type params() :: [param()]

Expand All @@ -69,7 +69,7 @@ defmodule I2C do
## Example:
`I2C.open([{:scl_io_num, 15}, {:sda_io_num, 4}, {:i2c_clock_hz, 1000000}])`
`I2C.open([{:scl, 15}, {:sda, 4}, {:clock_speed_hz, 1000000}])`
"""
@spec open(params()) :: pid()
def open(configuration) do
Expand Down
14 changes: 5 additions & 9 deletions src/platforms/esp32/components/avm_builtins/i2c_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,24 +108,20 @@ Context *i2c_driver_create_port(GlobalContext *global, term opts)
struct I2CData *i2c_data = calloc(1, sizeof(struct I2CData));
i2c_data->transmitting_pid = term_invalid_term();

term scl_io_num_term = interop_kv_get_value(
opts, ATOM_STR("\xA", "scl_io_num"), global);
term scl_io_num_term = interop_kv_get_value(opts, ATOM_STR("\x3", "scl"), global);
I2C_VALIDATE_NOT_INVALID(scl_io_num);

term sda_io_num_term = interop_kv_get_value(
opts, ATOM_STR("\xA", "sda_io_num"), global);
term sda_io_num_term = interop_kv_get_value(opts, ATOM_STR("\x3", "sda"), global);
I2C_VALIDATE_NOT_INVALID(sda_io_num);

term clock_hz_term = interop_kv_get_value(
opts, ATOM_STR("\xC", "i2c_clock_hz"), global);
term clock_hz_term = interop_kv_get_value(opts, ATOM_STR("\xE", "clock_speed_hz"), global);
I2C_VALIDATE_NOT_INVALID(clock_hz);

i2c_data->i2c_num = I2C_NUM_0;
term i2c_num_term = interop_kv_get_value(
opts, ATOM_STR("\x7", "i2c_num"), global);
term i2c_num_term = interop_kv_get_value(opts, ATOM_STR("\xA", "peripheral"), global);
if (!term_is_invalid_term(i2c_num_term)) {
if (!term_is_integer(i2c_num_term)) {
ESP_LOGE(TAG, "Invalid parameter: i2c_num is not an integer");
ESP_LOGE(TAG, "Invalid parameter: peripheral is not an integer");
goto free_and_exit;
}
i2c_data->i2c_num = term_to_int32(i2c_num_term);
Expand Down

0 comments on commit eb15ec9

Please sign in to comment.