mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-10-16 18:35:06 +00:00
Add Seeed Studio Wio Tracker L2 Pro (#676)
This commit is contained in:
parent
f8172446fd
commit
da2150aa83
195
Devices/seeed-wio-tracker-l2-pro/LICENSE-Apache-2.0.md
Normal file
195
Devices/seeed-wio-tracker-l2-pro/LICENSE-Apache-2.0.md
Normal file
@ -0,0 +1,195 @@
|
||||
Apache License
|
||||
==============
|
||||
|
||||
_Version 2.0, January 2004_
|
||||
_<<http://www.apache.org/licenses/>>_
|
||||
|
||||
### Terms and Conditions for use, reproduction, and distribution
|
||||
|
||||
#### 1. Definitions
|
||||
|
||||
“License” shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
“Licensor” shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
“Legal Entity” shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, “control” means **(i)** the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or **(iii)** beneficial ownership of such entity.
|
||||
|
||||
“You” (or “Your”) shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
“Source” form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
“Object” form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
“Work” shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
“Derivative Works” shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
“Contribution” shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
“submitted” means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as “Not a Contribution.”
|
||||
|
||||
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
#### 2. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
#### 3. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
#### 4. Redistribution
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
* **(b)** You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
#### 5. Submission of Contributions
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
#### 6. Trademarks
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
#### 7. Disclaimer of Warranty
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
#### 8. Limitation of Liability
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
#### 9. Accepting Warranty or Additional Liability
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
_END OF TERMS AND CONDITIONS_
|
||||
|
||||
### APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets `[]` replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same “printed page” as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
21
Devices/seeed-wio-tracker-l2-pro/device.properties
Normal file
21
Devices/seeed-wio-tracker-l2-pro/device.properties
Normal file
@ -0,0 +1,21 @@
|
||||
general.vendor=Seeed Studio
|
||||
general.name=Wio Tracker L2 Pro
|
||||
|
||||
apps.launcherAppId=tactility.launcher
|
||||
|
||||
hardware.target=ESP32S3
|
||||
hardware.flashSize=16MB
|
||||
hardware.spiRam=true
|
||||
hardware.spiRamMode=OCT
|
||||
hardware.spiRamSpeed=80M
|
||||
hardware.esptoolFlashFreq=80M
|
||||
hardware.tinyUsbMsc=true
|
||||
hardware.bluetooth=true
|
||||
|
||||
storage.userDataLocation=SD
|
||||
|
||||
display.size=3.2"
|
||||
display.shape=rectangle
|
||||
display.dpi=125
|
||||
|
||||
lvgl.colorDepth=16
|
||||
15
Devices/seeed-wio-tracker-l2-pro/module.yaml
Normal file
15
Devices/seeed-wio-tracker-l2-pro/module.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
dependencies:
|
||||
- Platforms/platform-esp32
|
||||
- Drivers/tca95xx-16bit-module
|
||||
- Drivers/ads1115-module
|
||||
- Drivers/button-control-module
|
||||
- Drivers/es7243e-module
|
||||
- Drivers/es8311-module
|
||||
- Drivers/audio-stream-module
|
||||
- Drivers/sx126x-module
|
||||
- Drivers/gt911-module
|
||||
- Drivers/lp5814-module
|
||||
- Drivers/nv3031b-module
|
||||
- Drivers/gps-generic-module
|
||||
dts: seeed,wio-tracker-l2-pro.dts
|
||||
dts-only: true
|
||||
270
Devices/seeed-wio-tracker-l2-pro/seeed,wio-tracker-l2-pro.dts
Normal file
270
Devices/seeed-wio-tracker-l2-pro/seeed,wio-tracker-l2-pro.dts
Normal file
@ -0,0 +1,270 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include <tactility/bindings/root.h>
|
||||
#include <tactility/bindings/battery_sense.h>
|
||||
#include <tactility/bindings/esp32_ble.h>
|
||||
#include <tactility/bindings/esp32_gpio.h>
|
||||
#include <tactility/bindings/esp32_grove.h>
|
||||
#include <tactility/bindings/esp32_i2c_master.h>
|
||||
#include <tactility/bindings/esp32_i2s.h>
|
||||
#include <tactility/bindings/esp32_sdmmc.h>
|
||||
#include <tactility/bindings/esp32_spi.h>
|
||||
#include <tactility/bindings/esp32_uart.h>
|
||||
#include <tactility/bindings/esp32_usbdevice.h>
|
||||
#include <tactility/bindings/esp32_wifi_pinned.h>
|
||||
#include <tactility/bindings/gpio_hog.h>
|
||||
#include <bindings/tca95xx.h>
|
||||
#include <bindings/ads1115.h>
|
||||
#include <bindings/button_control.h>
|
||||
#include <bindings/es7243e.h>
|
||||
#include <bindings/es8311.h>
|
||||
#include <bindings/gt911.h>
|
||||
#include <bindings/lp5814.h>
|
||||
#include <bindings/nv3031b.h>
|
||||
#include <bindings/sx1262.h>
|
||||
#include <gps_generic/bindings.h>
|
||||
|
||||
// Reference: https://wiki.seeedstudio.com/meshtastic_wio_tracker_l2_intro/
|
||||
/ {
|
||||
compatible = "root";
|
||||
model = "Seeed Studio Wio Tracker L2 Pro";
|
||||
|
||||
wifi0 {
|
||||
compatible = "espressif,esp32-wifi-pinned";
|
||||
};
|
||||
|
||||
ble0 {
|
||||
compatible = "espressif,esp32-ble";
|
||||
};
|
||||
|
||||
gpio0 {
|
||||
compatible = "espressif,esp32-gpio";
|
||||
gpio-count = <49>;
|
||||
};
|
||||
|
||||
// Declared before i2c0 so the codec can reference it
|
||||
i2s0 {
|
||||
compatible = "espressif,esp32-i2s";
|
||||
port = <I2S_NUM_0>;
|
||||
pin-mclk = <&gpio0 10 GPIO_FLAG_NONE>;
|
||||
pin-bclk = <&gpio0 11 GPIO_FLAG_NONE>;
|
||||
pin-ws = <&gpio0 12 GPIO_FLAG_NONE>;
|
||||
pin-data-out = <&gpio0 16 GPIO_FLAG_NONE>;
|
||||
pin-data-in = <&gpio0 15 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
i2c0 {
|
||||
compatible = "espressif,esp32-i2c-master";
|
||||
port = <I2C_NUM_0>;
|
||||
clock-frequency = <100000>;
|
||||
pin-sda = <&gpio0 47 GPIO_FLAG_NONE>;
|
||||
pin-scl = <&gpio0 48 GPIO_FLAG_NONE>;
|
||||
|
||||
// PCA9555, register compatible with the TCA9535
|
||||
pca9555 {
|
||||
compatible = "ti,tca9535";
|
||||
reg = <0x21>;
|
||||
|
||||
// Driven high by the vendor firmware. After a cold boot the audio codecs only answer with this high.
|
||||
pin4 {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 4 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
|
||||
};
|
||||
|
||||
lcd_power {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 5 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
|
||||
};
|
||||
|
||||
grove_power {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 7 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
|
||||
};
|
||||
|
||||
// Active high
|
||||
gnss_reset {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 9 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
|
||||
};
|
||||
|
||||
user_led {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 10 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
|
||||
};
|
||||
|
||||
usb_otg {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 11 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_LOW>;
|
||||
};
|
||||
|
||||
speaker_amplifier {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 12 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
|
||||
};
|
||||
|
||||
gnss_power {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 13 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
|
||||
};
|
||||
|
||||
sdcard_power {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 14 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
|
||||
};
|
||||
|
||||
battery_divider {
|
||||
compatible = "gpio-hog";
|
||||
pin = <&pca9555 15 GPIO_FLAG_NONE>;
|
||||
mode = <GPIO_HOG_MODE_OUTPUT_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
// Native orientation is portrait, the device is used in landscape
|
||||
touch {
|
||||
compatible = "goodix,gt911";
|
||||
reg = <0x5D>;
|
||||
x-max = <240>;
|
||||
y-max = <320>;
|
||||
swap-xy;
|
||||
mirror-y;
|
||||
pin-reset = <&pca9555 8 GPIO_FLAG_ACTIVE_LOW>;
|
||||
pin-interrupt = <&pca9555 3 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
// Speaker
|
||||
es8311 {
|
||||
compatible = "everest,es8311";
|
||||
reg = <0x18>;
|
||||
i2s = <&i2s0>;
|
||||
};
|
||||
|
||||
// Microphone
|
||||
es7243e {
|
||||
compatible = "everest,es7243e";
|
||||
reg = <0x14>;
|
||||
i2s = <&i2s0>;
|
||||
};
|
||||
|
||||
// Battery on AIN0 through a 1:2 divider that is enabled by expander pin 15
|
||||
ads1115 {
|
||||
compatible = "ti,ads1115";
|
||||
reg = <0x48>;
|
||||
full-scale-mv = <4096>;
|
||||
};
|
||||
|
||||
// Started at boot after the display is drawn
|
||||
display_backlight {
|
||||
compatible = "ti,lp5814";
|
||||
reg = <0x2C>;
|
||||
status = "disabled";
|
||||
// 40 mA per output, as in the vendor firmware
|
||||
high-current;
|
||||
dot-current = <200>;
|
||||
};
|
||||
};
|
||||
|
||||
battery-sense {
|
||||
compatible = "battery-sense";
|
||||
io-channel = <&ads1115 0>;
|
||||
reference-voltage-mv = <4096>;
|
||||
multiplier = <2000>;
|
||||
};
|
||||
|
||||
// WAKE: short press enter, long press back. BOOT: short press next, long press previous.
|
||||
buttons {
|
||||
compatible = "tactility,button-control";
|
||||
pin-primary = <&pca9555 0 GPIO_FLAG_NONE>;
|
||||
pin-secondary = <&gpio0 0 GPIO_FLAG_PULL_UP>;
|
||||
};
|
||||
|
||||
spi0 {
|
||||
compatible = "espressif,esp32-spi";
|
||||
host = <SPI2_HOST>;
|
||||
cs-gpios = <&gpio0 21 GPIO_FLAG_NONE>;
|
||||
pin-sclk = <&gpio0 4 GPIO_FLAG_NONE>;
|
||||
pin-mosi = <&gpio0 6 GPIO_FLAG_NONE>;
|
||||
pin-miso = <&gpio0 5 GPIO_FLAG_NONE>;
|
||||
|
||||
radio@0 {
|
||||
compatible = "semtech,sx1262";
|
||||
reg = <0>;
|
||||
pin-reset = <&gpio0 7 GPIO_FLAG_NONE>;
|
||||
pin-busy = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||
pin-dio1 = <&gpio0 9 GPIO_FLAG_NONE>;
|
||||
tcxo-millivolts = <3000>;
|
||||
dio2-as-rf-switch;
|
||||
};
|
||||
};
|
||||
|
||||
spi1 {
|
||||
compatible = "espressif,esp32-spi";
|
||||
host = <SPI3_HOST>;
|
||||
cs-gpios = <&gpio0 46 GPIO_FLAG_NONE>;
|
||||
pin-sclk = <&gpio0 42 GPIO_FLAG_NONE>;
|
||||
pin-mosi = <&gpio0 41 GPIO_FLAG_NONE>;
|
||||
pin-miso = <&gpio0 40 GPIO_FLAG_NONE>;
|
||||
pin-wp = <&gpio0 39 GPIO_FLAG_NONE>;
|
||||
pin-hd = <&gpio0 38 GPIO_FLAG_NONE>;
|
||||
|
||||
display@0 {
|
||||
compatible = "newvision,nv3031b";
|
||||
horizontal-resolution = <320>;
|
||||
vertical-resolution = <240>;
|
||||
swap-xy;
|
||||
mirror-y;
|
||||
pixel-clock-hz = <40000000>;
|
||||
pin-reset = <&pca9555 6 GPIO_FLAG_NONE>;
|
||||
backlight = <&display_backlight>;
|
||||
};
|
||||
};
|
||||
|
||||
sdmmc0 {
|
||||
compatible = "espressif,esp32-sdmmc";
|
||||
pin-clk = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||
pin-cmd = <&gpio0 3 GPIO_FLAG_NONE>;
|
||||
pin-d0 = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||
slot = <SDMMC_HOST_SLOT_1>;
|
||||
bus-width = <1>;
|
||||
};
|
||||
|
||||
uart_gps {
|
||||
compatible = "espressif,esp32-uart";
|
||||
port = <UART_NUM_1>;
|
||||
pin-tx = <&gpio0 17 GPIO_FLAG_NONE>;
|
||||
pin-rx = <&gpio0 18 GPIO_FLAG_NONE>;
|
||||
|
||||
gps {
|
||||
compatible = "tactility,gps-generic";
|
||||
status = "disabled";
|
||||
baud-rate = <9600>;
|
||||
};
|
||||
};
|
||||
|
||||
// Powered by expander pin 7
|
||||
grove0 {
|
||||
compatible = "espressif,esp32-grove";
|
||||
defaultMode = <GROVE_MODE_I2C>;
|
||||
pinSdaTx = <&gpio0 13 GPIO_FLAG_NONE>;
|
||||
pinSclRx = <&gpio0 14 GPIO_FLAG_NONE>;
|
||||
uartPort = <UART_NUM_2>;
|
||||
i2cPort = <I2C_NUM_1>;
|
||||
i2cClockFrequency = <400000>;
|
||||
};
|
||||
|
||||
usbdevice0 {
|
||||
compatible = "espressif,esp32-usbdevice";
|
||||
|
||||
usbdevicemsc0 {
|
||||
compatible = "espressif,esp32-usbdevice-msc";
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -22,6 +22,8 @@
|
||||
Check during installation process, but also when starting (SD card might have old app install from before Tactility OS update)
|
||||
- Support direct installation of an `.app` file with `tactility.py install --app helloworld.app`
|
||||
- minitar/untarFile(): "entry->metadata.path" can escape its confined path (e.g. "../something")
|
||||
- xl9555 and tca9534 drivers: support `GPIO_FLAG_ACTIVE_LOW` on outputs in software, like tca95xx does.
|
||||
Afterwards the raw level reset handling in cst66xx and tca8418 can use ACTIVE_LOW too.
|
||||
|
||||
## Medium Priority
|
||||
|
||||
|
||||
11
Drivers/ads1115-module/CMakeLists.txt
Normal file
11
Drivers/ads1115-module/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake")
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES "source/*.c*")
|
||||
|
||||
tactility_add_module(ads1115-module
|
||||
SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS include/
|
||||
REQUIRES TactilityKernel
|
||||
)
|
||||
195
Drivers/ads1115-module/LICENSE-Apache-2.0.md
Normal file
195
Drivers/ads1115-module/LICENSE-Apache-2.0.md
Normal file
@ -0,0 +1,195 @@
|
||||
Apache License
|
||||
==============
|
||||
|
||||
_Version 2.0, January 2004_
|
||||
_<<http://www.apache.org/licenses/>>_
|
||||
|
||||
### Terms and Conditions for use, reproduction, and distribution
|
||||
|
||||
#### 1. Definitions
|
||||
|
||||
“License” shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
“Licensor” shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
“Legal Entity” shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, “control” means **(i)** the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or **(iii)** beneficial ownership of such entity.
|
||||
|
||||
“You” (or “Your”) shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
“Source” form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
“Object” form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
“Work” shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
“Derivative Works” shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
“Contribution” shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
“submitted” means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as “Not a Contribution.”
|
||||
|
||||
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
#### 2. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
#### 3. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
#### 4. Redistribution
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
* **(b)** You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
#### 5. Submission of Contributions
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
#### 6. Trademarks
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
#### 7. Disclaimer of Warranty
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
#### 8. Limitation of Liability
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
#### 9. Accepting Warranty or Additional Liability
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
_END OF TERMS AND CONDITIONS_
|
||||
|
||||
### APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets `[]` replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same “printed page” as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
10
Drivers/ads1115-module/README.md
Normal file
10
Drivers/ads1115-module/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# ADS1115 ADC
|
||||
|
||||
A driver for the Texas Instruments `ADS1115` 16-bit I2C ADC, exposed as an ADC controller
|
||||
with the four single-ended inputs AIN0 to AIN3 as channels 0 to 3.
|
||||
|
||||
Each read is a single-shot conversion. The result is returned as a 12-bit value: 0 to 4095
|
||||
covers 0 V to the configured full-scale voltage, negative readings are returned as 0.
|
||||
Written from the TI datasheet (SBAS444).
|
||||
|
||||
License: [Apache v2.0](LICENSE-Apache-2.0.md)
|
||||
15
Drivers/ads1115-module/bindings/ti,ads1115.yaml
Normal file
15
Drivers/ads1115-module/bindings/ti,ads1115.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
description: >
|
||||
Texas Instruments ADS1115 16-bit ADC. Channels 0 to 3 are the single-ended inputs AIN0 to
|
||||
AIN3. Results are returned as 12-bit values, 0 to 4095 for 0 V to full-scale-mv.
|
||||
|
||||
include: ["i2c-device.yaml"]
|
||||
|
||||
compatible: "ti,ads1115"
|
||||
|
||||
bus: i2c
|
||||
|
||||
properties:
|
||||
full-scale-mv:
|
||||
type: int
|
||||
default: 4096
|
||||
description: Programmable gain amplifier full scale in millivolts (6144, 4096, 2048, 1024, 512 or 256)
|
||||
14
Drivers/ads1115-module/include/ads1115_module.h
Normal file
14
Drivers/ads1115-module/include/ads1115_module.h
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/module.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct Module ads1115_module;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
7
Drivers/ads1115-module/include/bindings/ads1115.h
Normal file
7
Drivers/ads1115-module/include/bindings/ads1115.h
Normal file
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <drivers/ads1115.h>
|
||||
|
||||
DEFINE_DEVICETREE(ads1115, struct Ads1115Config)
|
||||
17
Drivers/ads1115-module/include/drivers/ads1115.h
Normal file
17
Drivers/ads1115-module/include/drivers/ads1115.h
Normal file
@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct Ads1115Config {
|
||||
uint8_t address;
|
||||
uint16_t full_scale_mv;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
3
Drivers/ads1115-module/module.yaml
Normal file
3
Drivers/ads1115-module/module.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
- TactilityKernel
|
||||
bindings: bindings
|
||||
138
Drivers/ads1115-module/source/ads1115.cpp
Normal file
138
Drivers/ads1115-module/source/ads1115.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <drivers/ads1115.h>
|
||||
#include <ads1115_module.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/delay.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/adc_controller.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
constexpr auto* TAG = "ADS1115";
|
||||
#define GET_CONFIG(device) (static_cast<const Ads1115Config*>((device)->config))
|
||||
|
||||
static constexpr uint8_t REG_CONVERSION = 0x00;
|
||||
static constexpr uint8_t REG_CONFIG = 0x01;
|
||||
|
||||
static constexpr uint16_t CONFIG_OS = 1U << 15;
|
||||
static constexpr uint16_t CONFIG_MUX_SINGLE_AIN0 = 0b100U << 12;
|
||||
static constexpr uint16_t CONFIG_PGA_SHIFT = 9;
|
||||
static constexpr uint16_t CONFIG_MODE_SINGLE_SHOT = 1U << 8;
|
||||
static constexpr uint16_t CONFIG_DR_860_SPS = 0b111U << 5;
|
||||
static constexpr uint16_t CONFIG_COMP_QUE_DISABLE = 0b11U;
|
||||
|
||||
static constexpr uint8_t CHANNEL_COUNT = 4;
|
||||
// A conversion at 860 SPS takes about 1.2 ms
|
||||
static constexpr int CONVERSION_POLL_LIMIT = 10;
|
||||
|
||||
extern "C" {
|
||||
|
||||
static bool pga_bits_for(uint16_t full_scale_mv, uint16_t* out_bits) {
|
||||
static constexpr uint16_t FULL_SCALES_MV[] = { 6144, 4096, 2048, 1024, 512, 256 };
|
||||
for (uint16_t i = 0; i < sizeof(FULL_SCALES_MV) / sizeof(FULL_SCALES_MV[0]); i++) {
|
||||
if (FULL_SCALES_MV[i] == full_scale_mv) {
|
||||
*out_bits = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static error_t convert(Device* device, uint8_t channel, int16_t* out_code, TickType_t timeout) {
|
||||
const auto* config = GET_CONFIG(device);
|
||||
auto* i2c = device_get_parent(device);
|
||||
|
||||
uint16_t pga_bits = 0;
|
||||
check(pga_bits_for(config->full_scale_mv, &pga_bits));
|
||||
|
||||
uint16_t start = CONFIG_OS | (CONFIG_MUX_SINGLE_AIN0 + (static_cast<uint16_t>(channel) << 12)) | (pga_bits << CONFIG_PGA_SHIFT) |
|
||||
CONFIG_MODE_SINGLE_SHOT | CONFIG_DR_860_SPS | CONFIG_COMP_QUE_DISABLE;
|
||||
error_t error = i2c_controller_register16be_set(i2c, config->address, REG_CONFIG, start, timeout);
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
|
||||
// OS reads back as 1 once the conversion is done
|
||||
for (int i = 0; i < CONVERSION_POLL_LIMIT; i++) {
|
||||
delay_millis(1);
|
||||
uint16_t status;
|
||||
error = i2c_controller_register16be_get(i2c, config->address, REG_CONFIG, &status, timeout);
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
if ((status & CONFIG_OS) != 0) {
|
||||
uint16_t code;
|
||||
error = i2c_controller_register16be_get(i2c, config->address, REG_CONVERSION, &code, timeout);
|
||||
if (error == ERROR_NONE) {
|
||||
*out_code = static_cast<int16_t>(code);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_TIMEOUT;
|
||||
}
|
||||
|
||||
static error_t read_raw(Device* device, uint8_t channel, int* out_raw, TickType_t timeout) {
|
||||
if (channel >= CHANNEL_COUNT) {
|
||||
return ERROR_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
// A conversion is a sequence of transfers that must not interleave with another read
|
||||
device_lock(device);
|
||||
int16_t code = 0;
|
||||
error_t error = convert(device, channel, &code, timeout);
|
||||
device_unlock(device);
|
||||
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
|
||||
// 15 bits of positive range scaled to 12 bits
|
||||
*out_raw = code < 0 ? 0 : code >> 3;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static constexpr AdcControllerApi ADS1115_API = {
|
||||
.read_raw = read_raw
|
||||
};
|
||||
|
||||
static error_t start(Device* device) {
|
||||
check(device_get_type(device_get_parent(device)) == &I2C_CONTROLLER_TYPE);
|
||||
const auto* config = GET_CONFIG(device);
|
||||
|
||||
uint16_t pga_bits;
|
||||
if (!pga_bits_for(config->full_scale_mv, &pga_bits)) {
|
||||
LOG_E(TAG, "Unsupported full-scale-mv %u", config->full_scale_mv);
|
||||
return ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
uint16_t value;
|
||||
error_t error = i2c_controller_register16be_get(device_get_parent(device), config->address, REG_CONFIG, &value, pdMS_TO_TICKS(50));
|
||||
if (error != ERROR_NONE) {
|
||||
LOG_E(TAG, "Not responding at 0x%02X", config->address);
|
||||
return error;
|
||||
}
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop(Device*) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
Driver ads1115_driver = {
|
||||
.name = "ads1115",
|
||||
.compatible = (const char*[]) { "ti,ads1115", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.probe = nullptr,
|
||||
.api = &ADS1115_API,
|
||||
.device_type = &ADC_CONTROLLER_TYPE,
|
||||
.owner = &ads1115_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
}
|
||||
23
Drivers/ads1115-module/source/module.cpp
Normal file
23
Drivers/ads1115-module/source/module.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern Driver ads1115_driver;
|
||||
|
||||
static Driver* const ads1115_drivers[] = {
|
||||
&ads1115_driver,
|
||||
nullptr
|
||||
};
|
||||
|
||||
Module ads1115_module = {
|
||||
.name = "ads1115",
|
||||
.start = nullptr,
|
||||
.stop = nullptr,
|
||||
.drivers = ads1115_drivers,
|
||||
.symbols = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
11
Drivers/es7243e-module/CMakeLists.txt
Normal file
11
Drivers/es7243e-module/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake")
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES "source/*.c*")
|
||||
|
||||
tactility_add_module(es7243e-module
|
||||
SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS include/
|
||||
REQUIRES TactilityKernel audio-codec-module esp_codec_dev
|
||||
)
|
||||
195
Drivers/es7243e-module/LICENSE-Apache-2.0.md
Normal file
195
Drivers/es7243e-module/LICENSE-Apache-2.0.md
Normal file
@ -0,0 +1,195 @@
|
||||
Apache License
|
||||
==============
|
||||
|
||||
_Version 2.0, January 2004_
|
||||
_<<http://www.apache.org/licenses/>>_
|
||||
|
||||
### Terms and Conditions for use, reproduction, and distribution
|
||||
|
||||
#### 1. Definitions
|
||||
|
||||
“License” shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
“Licensor” shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
“Legal Entity” shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, “control” means **(i)** the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or **(iii)** beneficial ownership of such entity.
|
||||
|
||||
“You” (or “Your”) shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
“Source” form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
“Object” form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
“Work” shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
“Derivative Works” shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
“Contribution” shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
“submitted” means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as “Not a Contribution.”
|
||||
|
||||
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
#### 2. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
#### 3. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
#### 4. Redistribution
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
* **(b)** You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
#### 5. Submission of Contributions
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
#### 6. Trademarks
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
#### 7. Disclaimer of Warranty
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
#### 8. Limitation of Liability
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
#### 9. Accepting Warranty or Additional Liability
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
_END OF TERMS AND CONDITIONS_
|
||||
|
||||
### APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets `[]` replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same “printed page” as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
10
Drivers/es7243e-module/README.md
Normal file
10
Drivers/es7243e-module/README.md
Normal file
@ -0,0 +1,10 @@
|
||||
# ES7243E microphone ADC
|
||||
|
||||
A driver for the `ES7243E` stereo audio ADC by Everest Semiconductor, wired as an
|
||||
input-only `AUDIO_CODEC_TYPE` device. The I2C bus is the device's parent, the I2S
|
||||
controller carrying the audio data is referenced via a devicetree phandle. The ADC
|
||||
runs as I2S slave with MCLK from the pad (MCLK = 256 x sample rate).
|
||||
|
||||
Wraps Espressif's `esp_codec_dev` ES7243E implementation.
|
||||
|
||||
License: [Apache v2.0](LICENSE-Apache-2.0.md)
|
||||
15
Drivers/es7243e-module/bindings/everest,es7243e.yaml
Normal file
15
Drivers/es7243e-module/bindings/everest,es7243e.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
description: Everest Semiconductor ES7243E stereo microphone ADC
|
||||
|
||||
include: ["i2c-device.yaml"]
|
||||
|
||||
compatible: "everest,es7243e"
|
||||
|
||||
properties:
|
||||
i2s:
|
||||
type: phandle
|
||||
required: true
|
||||
description: "I2S controller device that carries audio data"
|
||||
input-gain-percent:
|
||||
type: int
|
||||
default: 100
|
||||
description: "Extra digital gain multiplier applied by audio_stream on top of the ADC's hardware gain, as an integer percentage (100 = 1.0x)"
|
||||
15
Drivers/es7243e-module/include/bindings/es7243e.h
Normal file
15
Drivers/es7243e-module/include/bindings/es7243e.h
Normal file
@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <drivers/es7243e.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DEFINE_DEVICETREE(es7243e, struct Es7243eConfig)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
23
Drivers/es7243e-module/include/drivers/es7243e.h
Normal file
23
Drivers/es7243e-module/include/drivers/es7243e.h
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Es7243eConfig {
|
||||
/** I2C address on the bus */
|
||||
uint8_t address;
|
||||
/** I2S controller device that carries audio data */
|
||||
struct Device* i2s_device;
|
||||
/** Extra digital gain applied by audio_stream as an integer percentage (100 = 1.0x) */
|
||||
uint16_t input_gain_percent;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
14
Drivers/es7243e-module/include/es7243e_module.h
Normal file
14
Drivers/es7243e-module/include/es7243e_module.h
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/module.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct Module es7243e_module;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
3
Drivers/es7243e-module/module.yaml
Normal file
3
Drivers/es7243e-module/module.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
- TactilityKernel
|
||||
bindings: bindings
|
||||
328
Drivers/es7243e-module/source/es7243e.cpp
Normal file
328
Drivers/es7243e-module/source/es7243e.cpp
Normal file
@ -0,0 +1,328 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <drivers/es7243e.h>
|
||||
#include <es7243e_module.h>
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/audio_codec.h>
|
||||
#include <tactility/drivers/audio_codec_adapters.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/drivers/i2s_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <es7243e_adc.h>
|
||||
#include <esp_codec_dev.h>
|
||||
#include <esp_codec_dev_defaults.h>
|
||||
|
||||
constexpr auto* TAG = "ES7243E";
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t NATIVE_SAMPLE_RATE = 16000;
|
||||
constexpr uint8_t NATIVE_CHANNELS = 2;
|
||||
constexpr float MAX_INPUT_GAIN_DB = 37.5f;
|
||||
|
||||
struct Es7243eData {
|
||||
const audio_codec_ctrl_if_t* ctrl_if = nullptr;
|
||||
const audio_codec_data_if_t* data_if = nullptr;
|
||||
const audio_codec_if_t* codec_if = nullptr;
|
||||
esp_codec_dev_handle_t codec_device = nullptr;
|
||||
bool is_open = false;
|
||||
uint8_t open_bits_per_sample = 16;
|
||||
uint8_t open_channels = NATIVE_CHANNELS;
|
||||
uint32_t open_sample_rate = 0;
|
||||
float input_gain = 1.0f;
|
||||
};
|
||||
|
||||
#define GET_CONFIG(device) (static_cast<const Es7243eConfig*>((device)->config))
|
||||
#define GET_DATA(device) (static_cast<Es7243eData*>(device_get_driver_data(device)))
|
||||
|
||||
// region AudioCodecApi
|
||||
|
||||
error_t open(Device* device, const struct AudioCodecStreamConfig* config) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data->codec_device == nullptr) {
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
if (config->direction != AUDIO_CODEC_DIR_INPUT) {
|
||||
LOG_E(TAG, "ES7243E is input-only");
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
uint8_t channels = (config->channels == 1) ? 1 : NATIVE_CHANNELS;
|
||||
|
||||
if (data->is_open) {
|
||||
bool same_config = config->bits_per_sample == data->open_bits_per_sample
|
||||
&& channels == data->open_channels
|
||||
&& config->sample_rate == data->open_sample_rate;
|
||||
return same_config ? ERROR_NONE : ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
esp_codec_dev_sample_info_t sample_info = {
|
||||
.bits_per_sample = config->bits_per_sample,
|
||||
.channel = channels,
|
||||
.channel_mask = 0,
|
||||
.sample_rate = config->sample_rate,
|
||||
.mclk_multiple = 0,
|
||||
};
|
||||
|
||||
if (esp_codec_dev_open(data->codec_device, &sample_info) != ESP_CODEC_DEV_OK) {
|
||||
LOG_E(TAG, "Failed to open codec device");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
data->open_bits_per_sample = config->bits_per_sample;
|
||||
data->open_channels = channels;
|
||||
data->open_sample_rate = config->sample_rate;
|
||||
data->is_open = true;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t close(Device* device) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data->codec_device == nullptr) {
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
if (data->is_open) {
|
||||
esp_codec_dev_close(data->codec_device);
|
||||
data->is_open = false;
|
||||
}
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t read(Device* device, void* buffer, size_t size, size_t* bytes_read, TickType_t timeout) {
|
||||
(void) timeout;
|
||||
auto* data = GET_DATA(device);
|
||||
if (!data->is_open) {
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
int result = esp_codec_dev_read(data->codec_device, buffer, (int) size);
|
||||
if (result < 0) {
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
*bytes_read = (size_t) result;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t write(Device* device, const void* buffer, size_t size, size_t* bytes_written, TickType_t timeout) {
|
||||
(void) device;
|
||||
(void) buffer;
|
||||
(void) size;
|
||||
(void) bytes_written;
|
||||
(void) timeout;
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
error_t set_volume(Device* device, AudioCodecDirection direction, float volume_percent) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data->codec_device == nullptr || direction != AUDIO_CODEC_DIR_INPUT) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
float db = (volume_percent / 100.0f) * MAX_INPUT_GAIN_DB;
|
||||
return (esp_codec_dev_set_in_gain(data->codec_device, db) == ESP_CODEC_DEV_OK) ? ERROR_NONE : ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
error_t get_volume(Device* device, AudioCodecDirection direction, float* volume_percent) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data->codec_device == nullptr || direction != AUDIO_CODEC_DIR_INPUT) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
float db = 0.0f;
|
||||
if (esp_codec_dev_get_in_gain(data->codec_device, &db) != ESP_CODEC_DEV_OK) {
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
*volume_percent = (db / MAX_INPUT_GAIN_DB) * 100.0f;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t set_mute(Device* device, AudioCodecDirection direction, bool muted) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data->codec_device == nullptr || direction != AUDIO_CODEC_DIR_INPUT) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return (esp_codec_dev_set_in_mute(data->codec_device, muted) == ESP_CODEC_DEV_OK) ? ERROR_NONE : ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
error_t get_mute(Device* device, AudioCodecDirection direction, bool* muted) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data->codec_device == nullptr || direction != AUDIO_CODEC_DIR_INPUT) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return (esp_codec_dev_get_in_mute(data->codec_device, muted) == ESP_CODEC_DEV_OK) ? ERROR_NONE : ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
error_t get_native_channels(Device* device, AudioCodecDirection direction, uint8_t* channels) {
|
||||
(void) device;
|
||||
if (direction != AUDIO_CODEC_DIR_INPUT) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
*channels = NATIVE_CHANNELS;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t get_native_sample_rate(Device* device, AudioCodecDirection direction, uint32_t* rate_hz) {
|
||||
(void) device;
|
||||
if (direction != AUDIO_CODEC_DIR_INPUT) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
*rate_hz = NATIVE_SAMPLE_RATE;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t get_capabilities(Device* device, AudioCodecDirection* supported_directions) {
|
||||
(void) device;
|
||||
*supported_directions = AUDIO_CODEC_DIR_INPUT;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t get_input_gain_multiplier(Device* device, float* gain) {
|
||||
*gain = GET_DATA(device)->input_gain;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static const struct AudioCodecApi API = {
|
||||
.open = open,
|
||||
.close = close,
|
||||
.read = read,
|
||||
.write = write,
|
||||
.set_volume = set_volume,
|
||||
.get_volume = get_volume,
|
||||
.set_mute = set_mute,
|
||||
.get_mute = get_mute,
|
||||
.get_native_sample_rate = get_native_sample_rate,
|
||||
.get_native_channels = get_native_channels,
|
||||
.get_capabilities = get_capabilities,
|
||||
.get_input_gain_multiplier = get_input_gain_multiplier,
|
||||
};
|
||||
|
||||
// endregion
|
||||
|
||||
// region Driver lifecycle
|
||||
|
||||
void delete_interfaces(Es7243eData* data) {
|
||||
// The delete functions close their interface first
|
||||
if (data->codec_device != nullptr) {
|
||||
esp_codec_dev_delete(data->codec_device);
|
||||
}
|
||||
if (data->codec_if != nullptr) {
|
||||
audio_codec_delete_codec_if(data->codec_if);
|
||||
}
|
||||
if (data->data_if != nullptr) {
|
||||
audio_codec_delete_data_if(data->data_if);
|
||||
}
|
||||
if (data->ctrl_if != nullptr) {
|
||||
audio_codec_delete_ctrl_if(data->ctrl_if);
|
||||
}
|
||||
}
|
||||
|
||||
error_t start_device(Device* device) {
|
||||
const auto* config = GET_CONFIG(device);
|
||||
|
||||
auto* i2c_controller = device_get_parent(device);
|
||||
if (i2c_controller == nullptr || device_get_type(i2c_controller) != &I2C_CONTROLLER_TYPE) {
|
||||
LOG_E(TAG, "Parent is not an I2C controller");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
auto* i2s_controller = config->i2s_device;
|
||||
if (i2s_controller == nullptr || device_get_type(i2s_controller) != &I2S_CONTROLLER_TYPE) {
|
||||
LOG_E(TAG, "I2S controller device is not valid");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
auto* data = new Es7243eData();
|
||||
data->input_gain = (float) config->input_gain_percent / 100.0f;
|
||||
|
||||
data->ctrl_if = audio_codec_adapter_new_i2c_ctrl(i2c_controller, config->address);
|
||||
data->data_if = audio_codec_adapter_new_i2s_data(i2s_controller);
|
||||
bool ok = data->ctrl_if != nullptr && data->data_if != nullptr;
|
||||
if (!ok) {
|
||||
LOG_E(TAG, "Failed to create adapters");
|
||||
}
|
||||
|
||||
if (ok && data->ctrl_if->open(data->ctrl_if, nullptr, 0) != ESP_CODEC_DEV_OK) {
|
||||
LOG_E(TAG, "Failed to open control interface");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (ok && data->data_if->open(data->data_if, nullptr, 0) != ESP_CODEC_DEV_OK) {
|
||||
LOG_E(TAG, "Failed to open data interface");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
es7243e_codec_cfg_t codec_config = {};
|
||||
codec_config.ctrl_if = data->ctrl_if;
|
||||
data->codec_if = es7243e_codec_new(&codec_config);
|
||||
if (data->codec_if == nullptr) {
|
||||
LOG_E(TAG, "Failed to create ES7243E codec interface");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
esp_codec_dev_cfg_t dev_config = {
|
||||
.dev_type = ESP_CODEC_DEV_TYPE_IN,
|
||||
.codec_if = data->codec_if,
|
||||
.data_if = data->data_if,
|
||||
};
|
||||
data->codec_device = esp_codec_dev_new(&dev_config);
|
||||
if (data->codec_device == nullptr) {
|
||||
LOG_E(TAG, "Failed to create codec device");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
delete_interfaces(data);
|
||||
delete data;
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
device_set_driver_data(device, data);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t stop_device(Device* device) {
|
||||
auto* data = GET_DATA(device);
|
||||
if (data == nullptr) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
if (data->is_open) {
|
||||
esp_codec_dev_close(data->codec_device);
|
||||
}
|
||||
delete_interfaces(data);
|
||||
|
||||
device_set_driver_data(device, nullptr);
|
||||
delete data;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
Driver es7243e_driver = {
|
||||
.name = "es7243e",
|
||||
.compatible = (const char*[]) { "everest,es7243e", nullptr },
|
||||
.start_device = start_device,
|
||||
.stop_device = stop_device,
|
||||
.probe = nullptr,
|
||||
.api = &API,
|
||||
.device_type = &AUDIO_CODEC_TYPE,
|
||||
.owner = &es7243e_module,
|
||||
.internal = nullptr,
|
||||
};
|
||||
|
||||
}
|
||||
23
Drivers/es7243e-module/source/module.cpp
Normal file
23
Drivers/es7243e-module/source/module.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern Driver es7243e_driver;
|
||||
|
||||
static Driver* const es7243e_drivers[] = {
|
||||
&es7243e_driver,
|
||||
nullptr
|
||||
};
|
||||
|
||||
Module es7243e_module = {
|
||||
.name = "es7243e",
|
||||
.start = nullptr,
|
||||
.stop = nullptr,
|
||||
.drivers = es7243e_drivers,
|
||||
.symbols = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
@ -33,7 +33,8 @@ properties:
|
||||
description: |
|
||||
Reset GPIO pin. Reset polarity is set with the GPIO descriptor's ACTIVE_HIGH or
|
||||
ACTIVE_LOW flag (active-low is the GT911's native convention; boards that invert the
|
||||
reset line, e.g. Tulip 4 R11, use ACTIVE_HIGH).
|
||||
reset line, e.g. Tulip 4 R11, use ACTIVE_HIGH). Pins on an IO expander are supported, the
|
||||
driver then pulses the reset itself with the interrupt pin held low (address 0x5D).
|
||||
pin-interrupt:
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
|
||||
@ -69,6 +69,73 @@ static error_t reset_controller_pin(const GpioPinSpec& pin, uint8_t pulses) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static bool is_expander_pin(const GpioPinSpec& pin) {
|
||||
return pin.gpio_controller != nullptr && !driver_is_compatible(device_get_driver(pin.gpio_controller), "espressif,esp32-gpio");
|
||||
}
|
||||
|
||||
// esp_lcd_touch only accepts native pins, so the reset is done here with the reset polarity from
|
||||
// the pin flags. INT is held physically low while reset is released, which selects address 0x5D.
|
||||
static error_t reset_with_expander_pins(const GpioPinSpec& reset_pin, const GpioPinSpec& interrupt_pin, uint8_t pulses) {
|
||||
if (pulses == 0) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
GpioDescriptor* interrupt = nullptr;
|
||||
if (interrupt_pin.gpio_controller != nullptr) {
|
||||
interrupt = gpio_descriptor_acquire(interrupt_pin.gpio_controller, interrupt_pin.pin, GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
|
||||
if (interrupt == nullptr) {
|
||||
LOG_E(TAG, "Failed to acquire interrupt pin");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
}
|
||||
|
||||
GpioDescriptor* reset = nullptr;
|
||||
if (reset_pin.gpio_controller != nullptr) {
|
||||
reset = gpio_descriptor_acquire(reset_pin.gpio_controller, reset_pin.pin, reset_pin.flags | GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
|
||||
if (reset == nullptr) {
|
||||
LOG_E(TAG, "Failed to acquire reset pin");
|
||||
if (interrupt != nullptr) {
|
||||
gpio_descriptor_release(interrupt);
|
||||
}
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
}
|
||||
|
||||
error_t error = ERROR_NONE;
|
||||
if (interrupt != nullptr) {
|
||||
error = gpio_descriptor_set_level(interrupt, false);
|
||||
}
|
||||
for (uint8_t i = 0; error == ERROR_NONE && reset != nullptr && i < pulses; i++) {
|
||||
error = gpio_descriptor_set_level(reset, true);
|
||||
if (error == ERROR_NONE) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
error = gpio_descriptor_set_level(reset, false);
|
||||
}
|
||||
if (error == ERROR_NONE) {
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
}
|
||||
|
||||
if (interrupt != nullptr) {
|
||||
error_t release_error = gpio_descriptor_set_flags(interrupt, GPIO_FLAG_DIRECTION_INPUT);
|
||||
if (error == ERROR_NONE) {
|
||||
error = release_error;
|
||||
}
|
||||
gpio_descriptor_release(interrupt);
|
||||
}
|
||||
if (reset != nullptr) {
|
||||
gpio_descriptor_release(reset);
|
||||
}
|
||||
|
||||
if (error != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to reset controller");
|
||||
return error;
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(60));
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
// region Driver lifecycle
|
||||
|
||||
// GT911's I2C address depends on the controller's INT pin level at power-up (board-strapped, not
|
||||
@ -149,7 +216,10 @@ static error_t start(Device* device) {
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
error_t error = reset_controller_pin(config->pin_reset, config->reset_pulses);
|
||||
bool expander_pins = is_expander_pin(config->pin_reset) || is_expander_pin(config->pin_interrupt);
|
||||
error_t error = expander_pins
|
||||
? reset_with_expander_pins(config->pin_reset, config->pin_interrupt, config->reset_pulses)
|
||||
: reset_controller_pin(config->pin_reset, config->reset_pulses);
|
||||
if (error != ERROR_NONE) {
|
||||
free(internal);
|
||||
return error;
|
||||
@ -164,8 +234,8 @@ static error_t start(Device* device) {
|
||||
esp_lcd_touch_config_t touch_config = {
|
||||
.x_max = config->x_max,
|
||||
.y_max = config->y_max,
|
||||
.rst_gpio_num = pin_or_nc(config->pin_reset),
|
||||
.int_gpio_num = pin_or_nc(config->pin_interrupt),
|
||||
.rst_gpio_num = expander_pins ? GPIO_NUM_NC : pin_or_nc(config->pin_reset),
|
||||
.int_gpio_num = expander_pins ? GPIO_NUM_NC : pin_or_nc(config->pin_interrupt),
|
||||
// Reset polarity comes from the pin_reset descriptor's ACTIVE_HIGH/ACTIVE_LOW flag; the
|
||||
// interrupt line is fixed active-low in hardware.
|
||||
.levels = {
|
||||
|
||||
11
Drivers/lp5814-module/CMakeLists.txt
Normal file
11
Drivers/lp5814-module/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake")
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES "source/*.c*")
|
||||
|
||||
tactility_add_module(lp5814-module
|
||||
SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS include/
|
||||
REQUIRES TactilityKernel
|
||||
)
|
||||
195
Drivers/lp5814-module/LICENSE-Apache-2.0.md
Normal file
195
Drivers/lp5814-module/LICENSE-Apache-2.0.md
Normal file
@ -0,0 +1,195 @@
|
||||
Apache License
|
||||
==============
|
||||
|
||||
_Version 2.0, January 2004_
|
||||
_<<http://www.apache.org/licenses/>>_
|
||||
|
||||
### Terms and Conditions for use, reproduction, and distribution
|
||||
|
||||
#### 1. Definitions
|
||||
|
||||
“License” shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
“Licensor” shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
“Legal Entity” shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, “control” means **(i)** the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or **(iii)** beneficial ownership of such entity.
|
||||
|
||||
“You” (or “Your”) shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
“Source” form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
“Object” form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
“Work” shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
“Derivative Works” shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
“Contribution” shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
“submitted” means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as “Not a Contribution.”
|
||||
|
||||
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
#### 2. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
#### 3. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
#### 4. Redistribution
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
* **(b)** You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
#### 5. Submission of Contributions
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
#### 6. Trademarks
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
#### 7. Disclaimer of Warranty
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
#### 8. Limitation of Liability
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
#### 9. Accepting Warranty or Additional Liability
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
_END OF TERMS AND CONDITIONS_
|
||||
|
||||
### APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets `[]` replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same “printed page” as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
7
Drivers/lp5814-module/README.md
Normal file
7
Drivers/lp5814-module/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# LP5814 backlight
|
||||
|
||||
A backlight driver for the Texas Instruments `LP5814` 4-channel I2C LED driver.
|
||||
The selected outputs are driven together with manual PWM dimming.
|
||||
Written from the TI datasheet (SNVSCQ0A).
|
||||
|
||||
License: [Apache v2.0](LICENSE-Apache-2.0.md)
|
||||
27
Drivers/lp5814-module/bindings/ti,lp5814.yaml
Normal file
27
Drivers/lp5814-module/bindings/ti,lp5814.yaml
Normal file
@ -0,0 +1,27 @@
|
||||
description: >
|
||||
Texas Instruments LP5814 4-channel LED driver used as a display backlight.
|
||||
The outputs selected by channels are driven together with manual PWM dimming.
|
||||
|
||||
include: ["i2c-device.yaml"]
|
||||
|
||||
compatible: "ti,lp5814"
|
||||
|
||||
bus: i2c
|
||||
|
||||
properties:
|
||||
channels:
|
||||
type: int
|
||||
default: 15
|
||||
description: Bit mask of the outputs OUT0 to OUT3 that drive the backlight
|
||||
high-current:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Use a maximum output current of 51 mA instead of 25.5 mA
|
||||
dot-current:
|
||||
type: int
|
||||
default: 255
|
||||
description: Output current per enabled output in 1/255 of the maximum current [0,255], so 0.2 mA steps at 51 mA and 0.1 mA steps at 25.5 mA
|
||||
brightness-default:
|
||||
type: int
|
||||
default: 255
|
||||
description: Default brightness level (PWM duty in 1/255), applied by set_brightness_default()
|
||||
7
Drivers/lp5814-module/include/bindings/lp5814.h
Normal file
7
Drivers/lp5814-module/include/bindings/lp5814.h
Normal file
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <drivers/lp5814.h>
|
||||
|
||||
DEFINE_DEVICETREE(lp5814, struct Lp5814Config)
|
||||
25
Drivers/lp5814-module/include/drivers/lp5814.h
Normal file
25
Drivers/lp5814-module/include/drivers/lp5814.h
Normal file
@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct Lp5814Config {
|
||||
uint8_t address;
|
||||
// Bit mask of OUT0 to OUT3
|
||||
uint8_t channels;
|
||||
// Maximum output current: 51 mA when true, 25.5 mA when false
|
||||
bool high_current;
|
||||
// Output current per enabled output in 1/255 of the maximum current: 0.2 mA steps at 51 mA, 0.1 mA steps at 25.5 mA
|
||||
uint8_t dot_current;
|
||||
// Default PWM duty in 1/255
|
||||
uint8_t brightness_default;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
14
Drivers/lp5814-module/include/lp5814_module.h
Normal file
14
Drivers/lp5814-module/include/lp5814_module.h
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/module.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct Module lp5814_module;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
3
Drivers/lp5814-module/module.yaml
Normal file
3
Drivers/lp5814-module/module.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
- TactilityKernel
|
||||
bindings: bindings
|
||||
165
Drivers/lp5814-module/source/lp5814.cpp
Normal file
165
Drivers/lp5814-module/source/lp5814.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <drivers/lp5814.h>
|
||||
#include <lp5814_module.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/delay.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/backlight.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
constexpr auto* TAG = "LP5814";
|
||||
#define GET_CONFIG(device) (static_cast<const Lp5814Config*>((device)->config))
|
||||
#define GET_INTERNAL(device) (static_cast<Lp5814Internal*>(device_get_driver_data(device)))
|
||||
|
||||
static const TickType_t I2C_TIMEOUT = pdMS_TO_TICKS(50);
|
||||
|
||||
static constexpr uint8_t REG_CHIP_EN = 0x00;
|
||||
static constexpr uint8_t REG_DEV_CONFIG0 = 0x01;
|
||||
static constexpr uint8_t REG_DEV_CONFIG1 = 0x02;
|
||||
static constexpr uint8_t REG_RESET_CMD = 0x0E;
|
||||
static constexpr uint8_t REG_UPDATE_CMD = 0x0F;
|
||||
static constexpr uint8_t REG_OUT0_DC = 0x14;
|
||||
static constexpr uint8_t REG_OUT0_MANUAL_PWM = 0x18;
|
||||
|
||||
static constexpr uint8_t RESET_KEY = 0xCC;
|
||||
static constexpr uint8_t UPDATE_KEY = 0x55;
|
||||
static constexpr uint8_t CHANNEL_COUNT = 4;
|
||||
|
||||
extern "C" {
|
||||
|
||||
struct Lp5814Internal {
|
||||
uint8_t brightness;
|
||||
};
|
||||
|
||||
static error_t write_register(Device* device, uint8_t reg, uint8_t value) {
|
||||
return i2c_controller_register8_set(device_get_parent(device), GET_CONFIG(device)->address, reg, value, I2C_TIMEOUT);
|
||||
}
|
||||
|
||||
static error_t write_per_channel(Device* device, uint8_t first_reg, uint8_t value) {
|
||||
const auto* config = GET_CONFIG(device);
|
||||
uint8_t values[CHANNEL_COUNT];
|
||||
for (uint8_t i = 0; i < CHANNEL_COUNT; i++) {
|
||||
values[i] = (config->channels & (1U << i)) != 0 ? value : 0;
|
||||
}
|
||||
return i2c_controller_write_register(device_get_parent(device), config->address, first_reg, values, CHANNEL_COUNT, I2C_TIMEOUT);
|
||||
}
|
||||
|
||||
// Registers 0x01 to 0x05 only take effect after the update command
|
||||
static error_t configure(Device* device) {
|
||||
const auto* config = GET_CONFIG(device);
|
||||
|
||||
error_t error = write_register(device, REG_RESET_CMD, RESET_KEY);
|
||||
if (error == ERROR_NONE) {
|
||||
delay_millis(1);
|
||||
error = write_register(device, REG_CHIP_EN, 0x01);
|
||||
}
|
||||
if (error == ERROR_NONE) {
|
||||
error = write_register(device, REG_DEV_CONFIG0, config->high_current ? 0x01 : 0x00);
|
||||
}
|
||||
if (error == ERROR_NONE) {
|
||||
error = write_register(device, REG_DEV_CONFIG1, config->channels & 0x0F);
|
||||
}
|
||||
if (error == ERROR_NONE) {
|
||||
error = write_register(device, REG_UPDATE_CMD, UPDATE_KEY);
|
||||
}
|
||||
if (error == ERROR_NONE) {
|
||||
error = write_per_channel(device, REG_OUT0_DC, config->dot_current);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// region BacklightApi
|
||||
|
||||
static error_t lp5814_set_brightness(Device* device, uint8_t brightness) {
|
||||
error_t error = write_per_channel(device, REG_OUT0_MANUAL_PWM, brightness);
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
GET_INTERNAL(device)->brightness = brightness;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t lp5814_set_brightness_default(Device* device) {
|
||||
return lp5814_set_brightness(device, GET_CONFIG(device)->brightness_default);
|
||||
}
|
||||
|
||||
static error_t lp5814_get_brightness(Device* device, uint8_t* out_brightness) {
|
||||
*out_brightness = GET_INTERNAL(device)->brightness;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static uint8_t lp5814_get_min_brightness(Device*) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t lp5814_get_max_brightness(Device*) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
static constexpr BacklightApi LP5814_BACKLIGHT_API = {
|
||||
.set_brightness = lp5814_set_brightness,
|
||||
.set_brightness_default = lp5814_set_brightness_default,
|
||||
.get_brightness = lp5814_get_brightness,
|
||||
.get_min_brightness = lp5814_get_min_brightness,
|
||||
.get_max_brightness = lp5814_get_max_brightness,
|
||||
};
|
||||
|
||||
// region Driver lifecycle
|
||||
|
||||
static error_t start(Device* device) {
|
||||
check(device_get_type(device_get_parent(device)) == &I2C_CONTROLLER_TYPE);
|
||||
|
||||
auto* internal = new(std::nothrow) Lp5814Internal { .brightness = 0 };
|
||||
if (internal == nullptr) {
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
device_set_driver_data(device, internal);
|
||||
|
||||
error_t error = configure(device);
|
||||
if (error == ERROR_NONE) {
|
||||
error = lp5814_set_brightness_default(device);
|
||||
}
|
||||
if (error != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to configure");
|
||||
device_set_driver_data(device, nullptr);
|
||||
delete internal;
|
||||
return error;
|
||||
}
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop(Device* device) {
|
||||
// Allowed to fail, the device is stopped either way
|
||||
lp5814_set_brightness(device, 0);
|
||||
write_register(device, REG_CHIP_EN, 0x00);
|
||||
|
||||
auto* internal = GET_INTERNAL(device);
|
||||
device_set_driver_data(device, nullptr);
|
||||
delete internal;
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
Driver lp5814_driver = {
|
||||
.name = "lp5814",
|
||||
.compatible = (const char*[]) { "ti,lp5814", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.probe = nullptr,
|
||||
.api = &LP5814_BACKLIGHT_API,
|
||||
.device_type = &BACKLIGHT_TYPE,
|
||||
.owner = &lp5814_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
}
|
||||
23
Drivers/lp5814-module/source/module.cpp
Normal file
23
Drivers/lp5814-module/source/module.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern Driver lp5814_driver;
|
||||
|
||||
static Driver* const lp5814_drivers[] = {
|
||||
&lp5814_driver,
|
||||
nullptr
|
||||
};
|
||||
|
||||
Module lp5814_module = {
|
||||
.name = "lp5814",
|
||||
.start = nullptr,
|
||||
.stop = nullptr,
|
||||
.drivers = lp5814_drivers,
|
||||
.symbols = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
11
Drivers/nv3031b-module/CMakeLists.txt
Normal file
11
Drivers/nv3031b-module/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake")
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES "source/*.c*")
|
||||
|
||||
tactility_add_module(nv3031b-module
|
||||
SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS include/
|
||||
REQUIRES TactilityKernel platform-esp32 esp_lcd
|
||||
)
|
||||
195
Drivers/nv3031b-module/LICENSE-Apache-2.0.md
Normal file
195
Drivers/nv3031b-module/LICENSE-Apache-2.0.md
Normal file
@ -0,0 +1,195 @@
|
||||
Apache License
|
||||
==============
|
||||
|
||||
_Version 2.0, January 2004_
|
||||
_<<http://www.apache.org/licenses/>>_
|
||||
|
||||
### Terms and Conditions for use, reproduction, and distribution
|
||||
|
||||
#### 1. Definitions
|
||||
|
||||
“License” shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
“Licensor” shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
“Legal Entity” shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, “control” means **(i)** the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or **(iii)** beneficial ownership of such entity.
|
||||
|
||||
“You” (or “Your”) shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
“Source” form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
“Object” form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
“Work” shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
“Derivative Works” shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
“Contribution” shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
“submitted” means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as “Not a Contribution.”
|
||||
|
||||
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
#### 2. Grant of Copyright License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
#### 3. Grant of Patent License
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
#### 4. Redistribution
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
* **(b)** You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
#### 5. Submission of Contributions
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
#### 6. Trademarks
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
#### 7. Disclaimer of Warranty
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
#### 8. Limitation of Liability
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
#### 9. Accepting Warranty or Additional Liability
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
_END OF TERMS AND CONDITIONS_
|
||||
|
||||
### APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets `[]` replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same “printed page” as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
35
Drivers/nv3031b-module/LICENSE-BSD-2-Clause.md
Normal file
35
Drivers/nv3031b-module/LICENSE-BSD-2-Clause.md
Normal file
@ -0,0 +1,35 @@
|
||||
# BSD 2-Clause License (FreeBSD License)
|
||||
|
||||
Applies to `source/nv3031b_init_cmds.h`, which contains the initialization sequence from [LovyanGFX](https://github.com/lovyan03/LovyanGFX) (`src/lgfx/v1/panel/Panel_NV3031B.hpp`).
|
||||
|
||||
```
|
||||
Software License Agreement (FreeBSD License)
|
||||
|
||||
Copyright (c) 2020 lovyan03 (https://github.com/lovyan03)
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
```
|
||||
12
Drivers/nv3031b-module/README.md
Normal file
12
Drivers/nv3031b-module/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# NV3031B display
|
||||
|
||||
A driver for the `NV3031B` display panel by NewVision, over QSPI.
|
||||
|
||||
The esp_lcd panel (`esp_lcd_nv3031b.c`) is adapted from Espressif's
|
||||
[esp_lcd_sh8601](https://github.com/espressif/esp-iot-solution/tree/master/components/display/lcd/esp_lcd_sh8601),
|
||||
which uses the same QSPI command framing.
|
||||
|
||||
License:
|
||||
|
||||
- [Apache v2.0](LICENSE-Apache-2.0.md) for all files except the one below
|
||||
- [BSD 2-Clause](LICENSE-BSD-2-Clause.md) for `source/nv3031b_init_cmds.h`, the initialization sequence from [LovyanGFX](https://github.com/lovyan03/LovyanGFX)
|
||||
59
Drivers/nv3031b-module/bindings/newvision,nv3031b.yaml
Normal file
59
Drivers/nv3031b-module/bindings/newvision,nv3031b.yaml
Normal file
@ -0,0 +1,59 @@
|
||||
description: NewVision NV3031B display panel over QSPI
|
||||
|
||||
bus: spi
|
||||
|
||||
compatible: "newvision,nv3031b"
|
||||
|
||||
properties:
|
||||
horizontal-resolution:
|
||||
type: int
|
||||
required: true
|
||||
description: Horizontal resolution in pixels
|
||||
vertical-resolution:
|
||||
type: int
|
||||
required: true
|
||||
description: Vertical resolution in pixels
|
||||
gap-x:
|
||||
type: int
|
||||
default: 0
|
||||
description: X offset applied to all draw operations
|
||||
gap-y:
|
||||
type: int
|
||||
default: 0
|
||||
description: Y offset applied to all draw operations
|
||||
swap-xy:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Y axes
|
||||
mirror-x:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Mirror the X axis
|
||||
mirror-y:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Mirror the Y axis
|
||||
invert-color:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the panel's color output
|
||||
bgr-order:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Use BGR element order instead of RGB
|
||||
pixel-clock-hz:
|
||||
type: int
|
||||
default: 40000000
|
||||
description: SPI clock frequency in Hz
|
||||
transaction-queue-depth:
|
||||
type: int
|
||||
default: 10
|
||||
description: Size of the internal SPI transaction queue
|
||||
pin-reset:
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: Reset pin, driven active-low by the driver. Pins on an IO expander are supported.
|
||||
backlight:
|
||||
type: phandle
|
||||
default: "NULL"
|
||||
description: Optional reference to this display's backlight device
|
||||
7
Drivers/nv3031b-module/include/bindings/nv3031b.h
Normal file
7
Drivers/nv3031b-module/include/bindings/nv3031b.h
Normal file
@ -0,0 +1,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <drivers/nv3031b.h>
|
||||
|
||||
DEFINE_DEVICETREE(nv3031b, struct Nv3031bConfig)
|
||||
34
Drivers/nv3031b-module/include/drivers/nv3031b.h
Normal file
34
Drivers/nv3031b-module/include/drivers/nv3031b.h
Normal file
@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/gpio.h>
|
||||
|
||||
struct Nv3031bConfig {
|
||||
uint16_t horizontal_resolution;
|
||||
uint16_t vertical_resolution;
|
||||
int32_t gap_x;
|
||||
int32_t gap_y;
|
||||
bool swap_xy;
|
||||
bool mirror_x;
|
||||
bool mirror_y;
|
||||
bool invert_color;
|
||||
bool bgr_order;
|
||||
uint32_t pixel_clock_hz;
|
||||
uint8_t transaction_queue_depth;
|
||||
// Reset line, driven active-low. May be on an IO expander.
|
||||
struct GpioPinSpec pin_reset;
|
||||
// Optional reference to this display's backlight device, NULL if none.
|
||||
struct Device* backlight;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
47
Drivers/nv3031b-module/include/esp_lcd_nv3031b.h
Normal file
47
Drivers/nv3031b-module/include/esp_lcd_nv3031b.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileContributor: Adapted from esp_lcd_sh8601 for the NV3031B
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int cmd;
|
||||
const void *data;
|
||||
size_t data_bytes;
|
||||
unsigned int delay_ms;
|
||||
} nv3031b_lcd_init_cmd_t;
|
||||
|
||||
/**
|
||||
* @brief Vendor specific configuration, passed as `vendor_config` in `esp_lcd_panel_dev_config_t`.
|
||||
*
|
||||
* The panel is driven over QSPI: commands are sent as `0x02 0x00 <cmd> 0x00` on one line,
|
||||
* pixel data as `0x32 0x00 0x2C 0x00` followed by the data on four lines.
|
||||
*/
|
||||
typedef struct {
|
||||
const nv3031b_lcd_init_cmd_t *init_cmds; /*!< Initialization sequence, NULL for the built-in one */
|
||||
uint16_t init_cmds_size; /*!< Number of commands in init_cmds */
|
||||
} nv3031b_vendor_config_t;
|
||||
|
||||
/**
|
||||
* @brief Create an LCD panel for the NV3031B.
|
||||
*
|
||||
* @param[in] io LCD panel IO handle (SPI panel IO in quad mode with 32 bit commands)
|
||||
* @param[in] panel_dev_config General panel device configuration
|
||||
* @param[out] ret_panel Returned LCD panel handle
|
||||
* @return ESP_OK on success, otherwise an error code
|
||||
*/
|
||||
esp_err_t esp_lcd_new_panel_nv3031b(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
14
Drivers/nv3031b-module/include/nv3031b_module.h
Normal file
14
Drivers/nv3031b-module/include/nv3031b_module.h
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/module.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern struct Module nv3031b_module;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
4
Drivers/nv3031b-module/module.yaml
Normal file
4
Drivers/nv3031b-module/module.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
- TactilityKernel
|
||||
- Platforms/platform-esp32
|
||||
bindings: bindings
|
||||
304
Drivers/nv3031b-module/source/esp_lcd_nv3031b.c
Normal file
304
Drivers/nv3031b-module/source/esp_lcd_nv3031b.c
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileContributor: Adapted from esp_lcd_sh8601 for the NV3031B
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_lcd_panel_interface.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_vendor.h"
|
||||
#include "esp_lcd_panel_ops.h"
|
||||
#include "esp_lcd_panel_commands.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_lcd_nv3031b.h"
|
||||
#include "nv3031b_init_cmds.h"
|
||||
|
||||
#define LCD_OPCODE_WRITE_CMD (0x02ULL)
|
||||
#define LCD_OPCODE_WRITE_COLOR (0x32ULL)
|
||||
|
||||
#define NV3031B_RESET_DELAY_MS 120
|
||||
#define NV3031B_SLEEP_OUT_DELAY_MS 120
|
||||
|
||||
static const char *TAG = "nv3031b";
|
||||
|
||||
static esp_err_t panel_nv3031b_del(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_nv3031b_reset(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_nv3031b_init(esp_lcd_panel_t *panel);
|
||||
static esp_err_t panel_nv3031b_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data);
|
||||
static esp_err_t panel_nv3031b_invert_color(esp_lcd_panel_t *panel, bool invert_color_data);
|
||||
static esp_err_t panel_nv3031b_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y);
|
||||
static esp_err_t panel_nv3031b_swap_xy(esp_lcd_panel_t *panel, bool swap_axes);
|
||||
static esp_err_t panel_nv3031b_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap);
|
||||
static esp_err_t panel_nv3031b_disp_on_off(esp_lcd_panel_t *panel, bool on_off);
|
||||
|
||||
typedef struct {
|
||||
esp_lcd_panel_t base;
|
||||
esp_lcd_panel_io_handle_t io;
|
||||
int reset_gpio_num;
|
||||
int x_gap;
|
||||
int y_gap;
|
||||
uint8_t fb_bits_per_pixel;
|
||||
uint8_t madctl_val;
|
||||
uint8_t colmod_val;
|
||||
const nv3031b_lcd_init_cmd_t *init_cmds;
|
||||
uint16_t init_cmds_size;
|
||||
struct {
|
||||
unsigned int reset_level: 1;
|
||||
} flags;
|
||||
} nv3031b_panel_t;
|
||||
|
||||
esp_err_t esp_lcd_new_panel_nv3031b(const esp_lcd_panel_io_handle_t io, const esp_lcd_panel_dev_config_t *panel_dev_config, esp_lcd_panel_handle_t *ret_panel)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(io && panel_dev_config && ret_panel, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
nv3031b_panel_t *nv3031b = calloc(1, sizeof(nv3031b_panel_t));
|
||||
ESP_GOTO_ON_FALSE(nv3031b, ESP_ERR_NO_MEM, err, TAG, "no mem for nv3031b panel");
|
||||
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
gpio_config_t io_conf = {
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = 1ULL << panel_dev_config->reset_gpio_num,
|
||||
};
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&io_conf), err, TAG, "configure GPIO for RST line failed");
|
||||
}
|
||||
|
||||
switch (panel_dev_config->rgb_ele_order) {
|
||||
case LCD_RGB_ELEMENT_ORDER_RGB:
|
||||
nv3031b->madctl_val = 0;
|
||||
break;
|
||||
case LCD_RGB_ELEMENT_ORDER_BGR:
|
||||
nv3031b->madctl_val = LCD_CMD_BGR_BIT;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported color element order");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (panel_dev_config->bits_per_pixel) {
|
||||
case 16: // RGB565
|
||||
nv3031b->colmod_val = 0x55;
|
||||
nv3031b->fb_bits_per_pixel = 16;
|
||||
break;
|
||||
case 18: // RGB666, each component in the 6 high bits of a byte
|
||||
nv3031b->colmod_val = 0x66;
|
||||
nv3031b->fb_bits_per_pixel = 24;
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, err, TAG, "unsupported pixel width");
|
||||
break;
|
||||
}
|
||||
|
||||
nv3031b->io = io;
|
||||
nv3031b->reset_gpio_num = panel_dev_config->reset_gpio_num;
|
||||
nv3031b->flags.reset_level = panel_dev_config->flags.reset_active_high;
|
||||
const nv3031b_vendor_config_t *vendor_config = (const nv3031b_vendor_config_t *)panel_dev_config->vendor_config;
|
||||
if (vendor_config && vendor_config->init_cmds) {
|
||||
nv3031b->init_cmds = vendor_config->init_cmds;
|
||||
nv3031b->init_cmds_size = vendor_config->init_cmds_size;
|
||||
} else {
|
||||
nv3031b->init_cmds = nv3031b_init_cmds_default;
|
||||
nv3031b->init_cmds_size = sizeof(nv3031b_init_cmds_default) / sizeof(nv3031b_lcd_init_cmd_t);
|
||||
}
|
||||
nv3031b->base.del = panel_nv3031b_del;
|
||||
nv3031b->base.reset = panel_nv3031b_reset;
|
||||
nv3031b->base.init = panel_nv3031b_init;
|
||||
nv3031b->base.draw_bitmap = panel_nv3031b_draw_bitmap;
|
||||
nv3031b->base.invert_color = panel_nv3031b_invert_color;
|
||||
nv3031b->base.set_gap = panel_nv3031b_set_gap;
|
||||
nv3031b->base.mirror = panel_nv3031b_mirror;
|
||||
nv3031b->base.swap_xy = panel_nv3031b_swap_xy;
|
||||
nv3031b->base.disp_on_off = panel_nv3031b_disp_on_off;
|
||||
*ret_panel = &(nv3031b->base);
|
||||
ESP_LOGD(TAG, "new nv3031b panel @%p", nv3031b);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
if (nv3031b) {
|
||||
if (panel_dev_config->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(panel_dev_config->reset_gpio_num);
|
||||
}
|
||||
free(nv3031b);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t tx_param(esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *param, size_t param_size)
|
||||
{
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_CMD << 24;
|
||||
return esp_lcd_panel_io_tx_param(io, lcd_cmd, param, param_size);
|
||||
}
|
||||
|
||||
static esp_err_t tx_color(esp_lcd_panel_io_handle_t io, int lcd_cmd, const void *param, size_t param_size)
|
||||
{
|
||||
lcd_cmd &= 0xff;
|
||||
lcd_cmd <<= 8;
|
||||
lcd_cmd |= LCD_OPCODE_WRITE_COLOR << 24;
|
||||
return esp_lcd_panel_io_tx_color(io, lcd_cmd, param, param_size);
|
||||
}
|
||||
|
||||
static esp_err_t panel_nv3031b_del(esp_lcd_panel_t *panel)
|
||||
{
|
||||
nv3031b_panel_t *nv3031b = __containerof(panel, nv3031b_panel_t, base);
|
||||
|
||||
if (nv3031b->reset_gpio_num >= 0) {
|
||||
gpio_reset_pin(nv3031b->reset_gpio_num);
|
||||
}
|
||||
ESP_LOGD(TAG, "del nv3031b panel @%p", nv3031b);
|
||||
free(nv3031b);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_nv3031b_reset(esp_lcd_panel_t *panel)
|
||||
{
|
||||
nv3031b_panel_t *nv3031b = __containerof(panel, nv3031b_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = nv3031b->io;
|
||||
|
||||
if (nv3031b->reset_gpio_num >= 0) {
|
||||
gpio_set_level(nv3031b->reset_gpio_num, nv3031b->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_set_level(nv3031b->reset_gpio_num, !nv3031b->flags.reset_level);
|
||||
vTaskDelay(pdMS_TO_TICKS(NV3031B_RESET_DELAY_MS));
|
||||
} else {
|
||||
ESP_RETURN_ON_ERROR(tx_param(io, LCD_CMD_SWRESET, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(NV3031B_RESET_DELAY_MS));
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_nv3031b_init(esp_lcd_panel_t *panel)
|
||||
{
|
||||
nv3031b_panel_t *nv3031b = __containerof(panel, nv3031b_panel_t, base);
|
||||
esp_lcd_panel_io_handle_t io = nv3031b->io;
|
||||
|
||||
// A NOP frame first resynchronizes the QSPI interface
|
||||
ESP_RETURN_ON_ERROR(tx_param(io, LCD_CMD_NOP, NULL, 0), TAG, "send command failed");
|
||||
|
||||
for (int i = 0; i < nv3031b->init_cmds_size; i++) {
|
||||
const nv3031b_lcd_init_cmd_t *cmd = &nv3031b->init_cmds[i];
|
||||
ESP_RETURN_ON_ERROR(tx_param(io, cmd->cmd, cmd->data, cmd->data_bytes), TAG, "send command failed");
|
||||
if (cmd->delay_ms > 0) {
|
||||
vTaskDelay(pdMS_TO_TICKS(cmd->delay_ms));
|
||||
}
|
||||
}
|
||||
|
||||
ESP_RETURN_ON_ERROR(tx_param(io, LCD_CMD_COLMOD, (uint8_t[]) {
|
||||
nv3031b->colmod_val,
|
||||
}, 1), TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(tx_param(io, LCD_CMD_SLPOUT, NULL, 0), TAG, "send command failed");
|
||||
vTaskDelay(pdMS_TO_TICKS(NV3031B_SLEEP_OUT_DELAY_MS));
|
||||
ESP_RETURN_ON_ERROR(tx_param(io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
nv3031b->madctl_val,
|
||||
}, 1), TAG, "send command failed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_nv3031b_draw_bitmap(esp_lcd_panel_t *panel, int x_start, int y_start, int x_end, int y_end, const void *color_data)
|
||||
{
|
||||
nv3031b_panel_t *nv3031b = __containerof(panel, nv3031b_panel_t, base);
|
||||
assert((x_start < x_end) && (y_start < y_end) && "start position must be smaller than end position");
|
||||
esp_lcd_panel_io_handle_t io = nv3031b->io;
|
||||
|
||||
x_start += nv3031b->x_gap;
|
||||
x_end += nv3031b->x_gap;
|
||||
y_start += nv3031b->y_gap;
|
||||
y_end += nv3031b->y_gap;
|
||||
|
||||
ESP_RETURN_ON_ERROR(tx_param(io, LCD_CMD_CASET, (uint8_t[]) {
|
||||
(x_start >> 8) & 0xFF,
|
||||
x_start & 0xFF,
|
||||
((x_end - 1) >> 8) & 0xFF,
|
||||
(x_end - 1) & 0xFF,
|
||||
}, 4), TAG, "send command failed");
|
||||
ESP_RETURN_ON_ERROR(tx_param(io, LCD_CMD_RASET, (uint8_t[]) {
|
||||
(y_start >> 8) & 0xFF,
|
||||
y_start & 0xFF,
|
||||
((y_end - 1) >> 8) & 0xFF,
|
||||
(y_end - 1) & 0xFF,
|
||||
}, 4), TAG, "send command failed");
|
||||
|
||||
size_t len = (x_end - x_start) * (y_end - y_start) * nv3031b->fb_bits_per_pixel / 8;
|
||||
ESP_RETURN_ON_ERROR(tx_color(io, LCD_CMD_RAMWR, color_data, len), TAG, "send color data failed");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_nv3031b_invert_color(esp_lcd_panel_t *panel, bool invert_color_data)
|
||||
{
|
||||
nv3031b_panel_t *nv3031b = __containerof(panel, nv3031b_panel_t, base);
|
||||
int command = invert_color_data ? LCD_CMD_INVON : LCD_CMD_INVOFF;
|
||||
ESP_RETURN_ON_ERROR(tx_param(nv3031b->io, command, NULL, 0), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_nv3031b_mirror(esp_lcd_panel_t *panel, bool mirror_x, bool mirror_y)
|
||||
{
|
||||
nv3031b_panel_t *nv3031b = __containerof(panel, nv3031b_panel_t, base);
|
||||
|
||||
if (mirror_x) {
|
||||
nv3031b->madctl_val |= LCD_CMD_MX_BIT;
|
||||
} else {
|
||||
nv3031b->madctl_val &= ~LCD_CMD_MX_BIT;
|
||||
}
|
||||
if (mirror_y) {
|
||||
nv3031b->madctl_val |= LCD_CMD_MY_BIT;
|
||||
} else {
|
||||
nv3031b->madctl_val &= ~LCD_CMD_MY_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(nv3031b->io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
nv3031b->madctl_val
|
||||
}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_nv3031b_swap_xy(esp_lcd_panel_t *panel, bool swap_axes)
|
||||
{
|
||||
nv3031b_panel_t *nv3031b = __containerof(panel, nv3031b_panel_t, base);
|
||||
|
||||
if (swap_axes) {
|
||||
nv3031b->madctl_val |= LCD_CMD_MV_BIT;
|
||||
} else {
|
||||
nv3031b->madctl_val &= ~LCD_CMD_MV_BIT;
|
||||
}
|
||||
ESP_RETURN_ON_ERROR(tx_param(nv3031b->io, LCD_CMD_MADCTL, (uint8_t[]) {
|
||||
nv3031b->madctl_val
|
||||
}, 1), TAG, "send command failed");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_nv3031b_set_gap(esp_lcd_panel_t *panel, int x_gap, int y_gap)
|
||||
{
|
||||
nv3031b_panel_t *nv3031b = __containerof(panel, nv3031b_panel_t, base);
|
||||
nv3031b->x_gap = x_gap;
|
||||
nv3031b->y_gap = y_gap;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t panel_nv3031b_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
|
||||
{
|
||||
nv3031b_panel_t *nv3031b = __containerof(panel, nv3031b_panel_t, base);
|
||||
|
||||
if (on_off) {
|
||||
// DISPON needs one dummy parameter byte on this controller
|
||||
ESP_RETURN_ON_ERROR(tx_param(nv3031b->io, LCD_CMD_DISPON, (uint8_t[]) {
|
||||
0x00
|
||||
}, 1), TAG, "send command failed");
|
||||
} else {
|
||||
ESP_RETURN_ON_ERROR(tx_param(nv3031b->io, LCD_CMD_DISPOFF, NULL, 0), TAG, "send command failed");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
23
Drivers/nv3031b-module/source/module.cpp
Normal file
23
Drivers/nv3031b-module/source/module.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern Driver nv3031b_driver;
|
||||
|
||||
static Driver* const nv3031b_drivers[] = {
|
||||
&nv3031b_driver,
|
||||
nullptr
|
||||
};
|
||||
|
||||
Module nv3031b_module = {
|
||||
.name = "nv3031b",
|
||||
.start = nullptr,
|
||||
.stop = nullptr,
|
||||
.drivers = nv3031b_drivers,
|
||||
.symbols = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
379
Drivers/nv3031b-module/source/nv3031b.cpp
Normal file
379
Drivers/nv3031b-module/source/nv3031b.cpp
Normal file
@ -0,0 +1,379 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <drivers/nv3031b.h>
|
||||
#include <nv3031b_module.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/delay.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/drivers/display.h>
|
||||
#include <tactility/drivers/esp32_spi.h>
|
||||
#include <tactility/drivers/gpio_controller.h>
|
||||
#include <tactility/drivers/spi_controller.h>
|
||||
#include <tactility/error.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <esp_err.h>
|
||||
#include <esp_lcd_io_spi.h>
|
||||
#include <esp_lcd_nv3031b.h>
|
||||
#include <esp_lcd_panel_io.h>
|
||||
#include <esp_lcd_panel_ops.h>
|
||||
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
constexpr auto* TAG = "NV3031B";
|
||||
#define GET_CONFIG(device) (static_cast<const Nv3031bConfig*>((device)->config))
|
||||
|
||||
struct Nv3031bInternal {
|
||||
Device* spi_controller;
|
||||
esp_lcd_panel_io_handle_t io_handle;
|
||||
esp_lcd_panel_handle_t panel_handle;
|
||||
// draw_bitmap() must block until the transfer physically completes
|
||||
SemaphoreHandle_t draw_done_semaphore;
|
||||
};
|
||||
|
||||
static bool IRAM_ATTR on_color_trans_done(esp_lcd_panel_io_handle_t, esp_lcd_panel_io_event_data_t*, void* user_ctx) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(user_ctx);
|
||||
BaseType_t high_task_woken = pdFALSE;
|
||||
xSemaphoreGiveFromISR(internal->draw_done_semaphore, &high_task_woken);
|
||||
return high_task_woken == pdTRUE;
|
||||
}
|
||||
|
||||
static int pin_or_unused(const struct GpioPinSpec& pin) {
|
||||
return pin.gpio_controller == nullptr ? -1 : static_cast<int>(pin.pin);
|
||||
}
|
||||
|
||||
// The reset line of the NV3031B is active-low
|
||||
static error_t hardware_reset(const struct GpioPinSpec& pin) {
|
||||
if (pin.gpio_controller == nullptr) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
auto* reset = gpio_descriptor_acquire(pin.gpio_controller, pin.pin, GPIO_FLAG_DIRECTION_OUTPUT | GPIO_FLAG_ACTIVE_LOW, GPIO_OWNER_GPIO);
|
||||
if (reset == nullptr) {
|
||||
LOG_E(TAG, "Failed to acquire reset pin");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
error_t error = gpio_descriptor_set_level(reset, true);
|
||||
if (error == ERROR_NONE) {
|
||||
delay_millis(10);
|
||||
error = gpio_descriptor_set_level(reset, false);
|
||||
}
|
||||
gpio_descriptor_release(reset);
|
||||
if (error != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to pulse reset pin");
|
||||
return error;
|
||||
}
|
||||
|
||||
delay_millis(120);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
// region Driver lifecycle
|
||||
|
||||
static error_t start(Device* device) {
|
||||
auto* parent = device_get_parent(device);
|
||||
check(device_get_type(parent) == &SPI_CONTROLLER_TYPE);
|
||||
|
||||
const auto* spi_config = static_cast<const Esp32SpiConfig*>(parent->config);
|
||||
const auto* config = GET_CONFIG(device);
|
||||
|
||||
struct GpioPinSpec cs_pin;
|
||||
if (esp32_spi_get_cs_pin(device, &cs_pin) != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to resolve CS pin");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
error_t error = hardware_reset(config->pin_reset);
|
||||
if (error != ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
|
||||
auto* internal = static_cast<Nv3031bInternal*>(malloc(sizeof(Nv3031bInternal)));
|
||||
if (internal == nullptr) {
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
internal->spi_controller = parent;
|
||||
internal->draw_done_semaphore = xSemaphoreCreateBinary();
|
||||
if (internal->draw_done_semaphore == nullptr) {
|
||||
free(internal);
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.cs_gpio_num = static_cast<gpio_num_t>(pin_or_unused(cs_pin)),
|
||||
.dc_gpio_num = GPIO_NUM_NC,
|
||||
.spi_mode = 3,
|
||||
.pclk_hz = config->pixel_clock_hz,
|
||||
.trans_queue_depth = config->transaction_queue_depth,
|
||||
.on_color_trans_done = on_color_trans_done,
|
||||
.user_ctx = internal,
|
||||
.lcd_cmd_bits = 32,
|
||||
.lcd_param_bits = 8,
|
||||
.cs_ena_pretrans = 0,
|
||||
.cs_ena_posttrans = 0,
|
||||
.flags = {
|
||||
.dc_high_on_cmd = 0,
|
||||
.dc_low_on_data = 0,
|
||||
.dc_low_on_param = 0,
|
||||
.octal_mode = 0,
|
||||
.quad_mode = 1,
|
||||
.sio_mode = 0,
|
||||
.psram_dma_direct = 0,
|
||||
.lsb_first = 0,
|
||||
.cs_high_active = 0,
|
||||
},
|
||||
};
|
||||
|
||||
esp_err_t ret = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)spi_config->host, &io_config, &internal->io_handle);
|
||||
if (ret != ESP_OK) {
|
||||
LOG_E(TAG, "Failed to create panel IO: %s", esp_err_to_name(ret));
|
||||
vSemaphoreDelete(internal->draw_done_semaphore);
|
||||
free(internal);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
nv3031b_vendor_config_t vendor_config = {
|
||||
.init_cmds = nullptr,
|
||||
.init_cmds_size = 0,
|
||||
};
|
||||
|
||||
// The hardware reset is done above, so the panel only gets a software reset
|
||||
esp_lcd_panel_dev_config_t panel_config = {
|
||||
.rgb_ele_order = config->bgr_order ? LCD_RGB_ELEMENT_ORDER_BGR : LCD_RGB_ELEMENT_ORDER_RGB,
|
||||
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
|
||||
.bits_per_pixel = 16,
|
||||
.reset_gpio_num = GPIO_NUM_NC,
|
||||
.vendor_config = &vendor_config,
|
||||
.flags = { .reset_active_high = false },
|
||||
};
|
||||
|
||||
ret = esp_lcd_new_panel_nv3031b(internal->io_handle, &panel_config, &internal->panel_handle);
|
||||
if (ret != ESP_OK) {
|
||||
LOG_E(TAG, "Failed to create panel: %s", esp_err_to_name(ret));
|
||||
esp_lcd_panel_io_del(internal->io_handle);
|
||||
vSemaphoreDelete(internal->draw_done_semaphore);
|
||||
free(internal);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
// Every failure path below must clean up fully: start_device is not retried by the kernel
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
bool ok =
|
||||
esp_lcd_panel_reset(internal->panel_handle) == ESP_OK &&
|
||||
esp_lcd_panel_init(internal->panel_handle) == ESP_OK;
|
||||
ok = ok && ((config->gap_x == 0 && config->gap_y == 0) || esp_lcd_panel_set_gap(internal->panel_handle, config->gap_x, config->gap_y) == ESP_OK);
|
||||
ok = ok && (!config->swap_xy || esp_lcd_panel_swap_xy(internal->panel_handle, true) == ESP_OK);
|
||||
ok = ok && ((!config->mirror_x && !config->mirror_y) || esp_lcd_panel_mirror(internal->panel_handle, config->mirror_x, config->mirror_y) == ESP_OK);
|
||||
ok = ok && esp_lcd_panel_invert_color(internal->panel_handle, config->invert_color) == ESP_OK;
|
||||
ok = ok && esp_lcd_panel_disp_on_off(internal->panel_handle, true) == ESP_OK;
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
|
||||
if (!ok) {
|
||||
LOG_E(TAG, "Failed to bring up panel");
|
||||
esp_lcd_panel_del(internal->panel_handle);
|
||||
esp_lcd_panel_io_del(internal->io_handle);
|
||||
vSemaphoreDelete(internal->draw_done_semaphore);
|
||||
free(internal);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
device_set_driver_data(device, internal);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop(Device* device) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(device_get_driver_data(device));
|
||||
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
if (internal->panel_handle != nullptr) {
|
||||
if (esp_lcd_panel_del(internal->panel_handle) != ESP_OK) {
|
||||
LOG_E(TAG, "Failed to delete panel");
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
internal->panel_handle = nullptr;
|
||||
}
|
||||
|
||||
if (internal->io_handle != nullptr) {
|
||||
if (esp_lcd_panel_io_del(internal->io_handle) != ESP_OK) {
|
||||
LOG_E(TAG, "Failed to delete panel IO");
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
internal->io_handle = nullptr;
|
||||
}
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
|
||||
vSemaphoreDelete(internal->draw_done_semaphore);
|
||||
free(internal);
|
||||
device_set_driver_data(device, nullptr);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region DisplayApi
|
||||
|
||||
static error_t nv3031b_reset(Device* device) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(device_get_driver_data(device));
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
error_t result = esp_lcd_panel_reset(internal->panel_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return result;
|
||||
}
|
||||
|
||||
static error_t nv3031b_init(Device* device) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(device_get_driver_data(device));
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
error_t result = esp_lcd_panel_init(internal->panel_handle) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return result;
|
||||
}
|
||||
|
||||
static error_t nv3031b_draw_bitmap(Device* device, int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end, const void* color_data) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(device_get_driver_data(device));
|
||||
|
||||
xSemaphoreTake(internal->draw_done_semaphore, 0);
|
||||
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
esp_err_t ret = esp_lcd_panel_draw_bitmap(internal->panel_handle, x_start, y_start, x_end, y_end, color_data);
|
||||
if (ret != ESP_OK) {
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
// The bus lock is held until the transfer is done so no other bus user can interleave
|
||||
xSemaphoreTake(internal->draw_done_semaphore, portMAX_DELAY);
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t nv3031b_mirror(Device* device, bool x_axis, bool y_axis) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(device_get_driver_data(device));
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
error_t result = esp_lcd_panel_mirror(internal->panel_handle, x_axis, y_axis) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return result;
|
||||
}
|
||||
|
||||
static error_t nv3031b_swap_xy(Device* device, bool swap_axes) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(device_get_driver_data(device));
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
error_t result = esp_lcd_panel_swap_xy(internal->panel_handle, swap_axes) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool nv3031b_get_swap_xy(Device* device) {
|
||||
return GET_CONFIG(device)->swap_xy;
|
||||
}
|
||||
|
||||
static bool nv3031b_get_mirror_x(Device* device) {
|
||||
return GET_CONFIG(device)->mirror_x;
|
||||
}
|
||||
|
||||
static bool nv3031b_get_mirror_y(Device* device) {
|
||||
return GET_CONFIG(device)->mirror_y;
|
||||
}
|
||||
|
||||
static error_t nv3031b_set_gap(Device* device, int32_t x_gap, int32_t y_gap) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(device_get_driver_data(device));
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
error_t result = esp_lcd_panel_set_gap(internal->panel_handle, x_gap, y_gap) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int32_t nv3031b_get_gap_x(Device* device) {
|
||||
return GET_CONFIG(device)->gap_x;
|
||||
}
|
||||
|
||||
static int32_t nv3031b_get_gap_y(Device* device) {
|
||||
return GET_CONFIG(device)->gap_y;
|
||||
}
|
||||
|
||||
static error_t nv3031b_invert_color(Device* device, bool invert_color_data) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(device_get_driver_data(device));
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
error_t result = esp_lcd_panel_invert_color(internal->panel_handle, invert_color_data) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return result;
|
||||
}
|
||||
|
||||
static error_t nv3031b_disp_on_off(Device* device, bool on_off) {
|
||||
auto* internal = static_cast<Nv3031bInternal*>(device_get_driver_data(device));
|
||||
spi_controller_lock(internal->spi_controller);
|
||||
error_t result = esp_lcd_panel_disp_on_off(internal->panel_handle, on_off) == ESP_OK ? ERROR_NONE : ERROR_RESOURCE;
|
||||
spi_controller_unlock(internal->spi_controller);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Pixels go out big-endian on the bus
|
||||
static enum DisplayColorFormat nv3031b_get_color_format(Device*) {
|
||||
return DISPLAY_COLOR_FORMAT_RGB565_SWAPPED;
|
||||
}
|
||||
|
||||
static uint16_t nv3031b_get_resolution_x(Device* device) {
|
||||
return GET_CONFIG(device)->horizontal_resolution;
|
||||
}
|
||||
|
||||
static uint16_t nv3031b_get_resolution_y(Device* device) {
|
||||
return GET_CONFIG(device)->vertical_resolution;
|
||||
}
|
||||
|
||||
static error_t nv3031b_get_backlight(Device* device, Device** backlight) {
|
||||
auto* configured_backlight = GET_CONFIG(device)->backlight;
|
||||
if (configured_backlight == nullptr) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
*backlight = configured_backlight;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
static const DisplayApi nv3031b_display_api = {
|
||||
.capabilities = DISPLAY_CAPABILITY_CAP_MIRROR | DISPLAY_CAPABILITY_CAP_SWAP_XY |
|
||||
DISPLAY_CAPABILITY_CAP_SET_GAP | DISPLAY_CAPABILITY_INVERT_COLOR | DISPLAY_CAPABILITY_ON_OFF |
|
||||
DISPLAY_CAPABILITY_BACKLIGHT,
|
||||
.reset = nv3031b_reset,
|
||||
.init = nv3031b_init,
|
||||
.draw_bitmap = nv3031b_draw_bitmap,
|
||||
.clear = nullptr,
|
||||
.refresh = nullptr,
|
||||
.mirror = nv3031b_mirror,
|
||||
.swap_xy = nv3031b_swap_xy,
|
||||
.get_swap_xy = nv3031b_get_swap_xy,
|
||||
.get_mirror_x = nv3031b_get_mirror_x,
|
||||
.get_mirror_y = nv3031b_get_mirror_y,
|
||||
.set_gap = nv3031b_set_gap,
|
||||
.get_gap_x = nv3031b_get_gap_x,
|
||||
.get_gap_y = nv3031b_get_gap_y,
|
||||
.invert_color = nv3031b_invert_color,
|
||||
.disp_on_off = nv3031b_disp_on_off,
|
||||
.disp_sleep = nullptr,
|
||||
.get_color_format = nv3031b_get_color_format,
|
||||
.get_resolution_x = nv3031b_get_resolution_x,
|
||||
.get_resolution_y = nv3031b_get_resolution_y,
|
||||
.get_frame_buffer = nullptr,
|
||||
.get_frame_buffer_count = nullptr,
|
||||
.get_backlight = nv3031b_get_backlight,
|
||||
.has_capability = nullptr,
|
||||
};
|
||||
|
||||
Driver nv3031b_driver = {
|
||||
.name = "nv3031b",
|
||||
.compatible = (const char*[]) { "newvision,nv3031b", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.probe = nullptr,
|
||||
.api = &nv3031b_display_api,
|
||||
.device_type = &DISPLAY_TYPE,
|
||||
.owner = &nv3031b_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
34
Drivers/nv3031b-module/source/nv3031b_init_cmds.h
Normal file
34
Drivers/nv3031b-module/source/nv3031b_init_cmds.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 lovyan03 (https://github.com/lovyan03)
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*
|
||||
* Initialization sequence from LovyanGFX src/lgfx/v1/panel/Panel_NV3031B.hpp
|
||||
* https://github.com/lovyan03/LovyanGFX
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "esp_lcd_nv3031b.h"
|
||||
|
||||
static const nv3031b_lcd_init_cmd_t nv3031b_init_cmds_default[] = {
|
||||
{0xFD, (uint8_t[]) {0x06, 0x08}, 2, 0},
|
||||
{0x60, (uint8_t[]) {0x0C}, 1, 0},
|
||||
{0x61, (uint8_t[]) {0x07, 0x04}, 2, 0},
|
||||
{0xB4, (uint8_t[]) {0x01}, 1, 0},
|
||||
{0xB1, (uint8_t[]) {0x0F, 0x02, 0x03}, 3, 0},
|
||||
{0xB5, (uint8_t[]) {0x02, 0x02, 0x0A, 0x14}, 4, 0},
|
||||
{0xB6, (uint8_t[]) {0x44, 0x01, 0x9F, 0x00, 0x02}, 5, 0},
|
||||
{0xDF, (uint8_t[]) {0x11}, 1, 0},
|
||||
{0x67, (uint8_t[]) {0x21}, 1, 0},
|
||||
{0x68, (uint8_t[]) {0x90, 0x4F, 0x27, 0x21}, 4, 0},
|
||||
{0xE1, (uint8_t[]) {0x20, 0x69}, 2, 0},
|
||||
{0xE4, (uint8_t[]) {0x69, 0x20}, 2, 0},
|
||||
{0xE2, (uint8_t[]) {0x10, 0x12, 0x12, 0x30, 0x39, 0x3F}, 6, 0},
|
||||
{0xE5, (uint8_t[]) {0x3F, 0x33, 0x2D, 0x12, 0x12, 0x10}, 6, 0},
|
||||
{0xE0, (uint8_t[]) {0x06, 0x06, 0x0B, 0x12, 0x11, 0x11, 0x0E, 0x19}, 8, 0},
|
||||
{0xE3, (uint8_t[]) {0x19, 0x13, 0x14, 0x14, 0x14, 0x12, 0x08, 0x05}, 8, 0},
|
||||
{0xE6, (uint8_t[]) {0x00, 0xFF}, 2, 0},
|
||||
{0xE7, (uint8_t[]) {0x01, 0x04, 0x03, 0x03, 0x00, 0x12}, 6, 0},
|
||||
{0xE8, (uint8_t[]) {0x00, 0x70, 0x00}, 3, 0},
|
||||
{0xEC, (uint8_t[]) {0x54}, 1, 0},
|
||||
{0xFD, (uint8_t[]) {0xFA, 0xFC}, 2, 0},
|
||||
};
|
||||
@ -6,6 +6,7 @@ pin): two 8-bit ports for input, output, polarity inversion, and direction, addr
|
||||
pins 0-15 (port 0 = pins 0-7, port 1 = pins 8-15).
|
||||
|
||||
It does not support pull-up/down resistors or high-impedance outputs; requesting those
|
||||
flags returns `ERROR_NOT_SUPPORTED`.
|
||||
flags returns `ERROR_NOT_SUPPORTED`. Active-low pins use the polarity register for reading
|
||||
and are inverted in software when driven as outputs.
|
||||
|
||||
License: [Apache v2.0](LICENSE-Apache-2.0.md)
|
||||
|
||||
@ -46,12 +46,14 @@ static error_t set_level(GpioDescriptor* descriptor, bool high) {
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
auto reg = static_cast<uint8_t>(TCA95XX_REGISTER_OUTPUT_PORT0 + port_of(descriptor));
|
||||
auto bit = bit_of(descriptor);
|
||||
// The output port has no polarity inversion, so active-low outputs are inverted here
|
||||
bool physical_high = (descriptor->flags & GPIO_FLAG_ACTIVE_LOW) != 0 ? !high : high;
|
||||
|
||||
// i2c_controller_register8_{set,reset}_bits() do a separate read then
|
||||
// write; without this lock, concurrent updates to different pins on the
|
||||
// same output port register can clobber each other.
|
||||
device_lock(device);
|
||||
error_t err = high
|
||||
error_t err = physical_high
|
||||
? i2c_controller_register8_set_bits(parent, address, reg, bit, portMAX_DELAY)
|
||||
: i2c_controller_register8_reset_bits(parent, address, reg, bit, portMAX_DELAY);
|
||||
device_unlock(device);
|
||||
@ -81,13 +83,6 @@ static error_t set_flags(GpioDescriptor* descriptor, gpio_flags_t flags) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
// The polarity register only inverts what's read back from an input pin;
|
||||
// set_level() still drives outputs at the raw level. Accepting ACTIVE_LOW
|
||||
// on an output would silently not do what it implies.
|
||||
if ((flags & GPIO_FLAG_ACTIVE_LOW) && (flags & GPIO_FLAG_DIRECTION_OUTPUT)) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
auto* device = descriptor->controller;
|
||||
auto* parent = device_get_parent(device);
|
||||
auto address = GET_CONFIG(device)->address;
|
||||
@ -113,7 +108,7 @@ static error_t set_flags(GpioDescriptor* descriptor, gpio_flags_t flags) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Polarity inversion (mainly relevant for active-low inputs).
|
||||
// Input polarity inversion, so get_level() reports the logical level of active-low pins
|
||||
if (flags & GPIO_FLAG_ACTIVE_LOW) {
|
||||
err = i2c_controller_register8_set_bits(parent, address, polarity_reg, bit, portMAX_DELAY);
|
||||
} else {
|
||||
|
||||
@ -24,6 +24,14 @@ Website: https://github.com/vroland/epdiy
|
||||
|
||||
License: [LGPL v3.0 or later](https://github.com/vroland/epdiy/blob/main/LICENSE)
|
||||
|
||||
### esp-iot-solution
|
||||
|
||||
The NV3031B panel driver (`Drivers/nv3031b-module`) is adapted from the `esp_lcd_sh8601` component.
|
||||
|
||||
Website: https://github.com/espressif/esp-iot-solution
|
||||
|
||||
License: [Apache License v2.0](https://github.com/espressif/esp-iot-solution/blob/master/LICENSE)
|
||||
|
||||
### ESP-IDF
|
||||
|
||||
This project uses ESP-IDF to compile the ESP32 firmware.
|
||||
@ -53,6 +61,14 @@ Website: https://github.com/nayarsystems/posix_tz_db
|
||||
|
||||
License: [MIT](https://github.com/nayarsystems/posix_tz_db/blob/master/LICENSE)
|
||||
|
||||
### LovyanGFX
|
||||
|
||||
The NV3031B initialization sequence in `Drivers/nv3031b-module/source/nv3031b_init_cmds.h` is taken from LovyanGFX.
|
||||
|
||||
Website: https://github.com/lovyan03/LovyanGFX
|
||||
|
||||
License: [FreeBSD (BSD 2-Clause)](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt)
|
||||
|
||||
### Minmea
|
||||
|
||||
Website: https://github.com/kosma/minmea
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user