1. Device Tree 관련설정
Device Tree 기본문법이해
Device Tree 기반 부팅방법
아래설정은 i.MX8에서 BSP에서 LSIO PWM 관련설정이 없어 어쩔수 없이 Datasheet를 보고 직접 만들어서 추가하였으며, MIPI에서 사용하는 PWM과 같이 i.mx27로 사용결정
$ vi *dts /* PWM 사용을 위해서 PWM 사용과 GPIO PINMUX 설정 iomuxc가 label 이므로 &iomuxc 사용 (iomuxc: pinctrl) */ &iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog>; /* PINMUX 를 PWM과 GPIO 변경 * IMX8QXP_UART1_RX : PWM1 * IMX8QXP_UART1_TX : GPIO */ pinctrl_lppwm1: lppwm1grp { fsl,pins = < IMX8QXP_UART1_RX_LSIO_PWM1_OUT 0x00000020 IMX8QXP_UART1_TX_LSIO_GPIO0_IO21 0x00000020 >; }; /* PINMUX 를 PWM과 GPIO 변경 * IMX8QXP_UART1_RTS_B : PWM2 * IMX8QXP_UART1_CTS_B : GPIO */ pinctrl_lppwm2: lppwm2grp { fsl,pins = < IMX8QXP_UART1_RTS_B_LSIO_PWM2_OUT 0x00000020 IMX8QXP_UART1_CTS_B_LSIO_GPIO0_IO24 0x00000020 >; }; }; /* MIPI의 PWM 부분 삭제 전부 label이므로 &적용 */ /delete-node/ &pwm_mipi_lvds0; /delete-node/ &pwm_mipi_lvds1; /delete-node/ &lvds_backlight0; /delete-node/ &lvds_backlight1; /* UART1 과 PWM PINMUX 충돌하여 미사용로 변경 */ &lpuart1 { status = "disabled"; }; /* LSIO PWM 관련정의가 없어서 Datasheet를 보고 각 Address에 맞춰 정의 MIPI도 i.MX6도 PWM을 im27-pwm 사용하여 나 또한 이것으로 사용하기로 결정 lsio_subsys를 main으로 넣기로함 / { ..... } */ / { lsio_subsys: bus@5d000000 { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x5d000000 0x0 0x5d000000 0x1000000>, <0x08000000 0x0 0x08000000 0x10000000>; /* i.MXQXP의 LSIO Datasheet 관련부분을 보면 상위 Memory Map Range 영역을 설정 현재 child's address 1 , size 1만 존재 parent address가 없음 총 4개로 memory mapped io로 하는 것으로 생각됨 (추측) - Physical Start 0x5d000000 0x0 - Physical End 0x5d000000+0x1000000 - Virtual Start 0x08000000 0x0 - Virtual End 0x08000000+0x10000000 */ pwm1_lsio: pwm@5d010000 { compatible = "fsl,imx8qxp-pwm", "fsl,imx27-pwm"; reg = <0x5d010000 0x1000>; clocks = <&pwm1_lpcg 0>, <&pwm1_lpcg 1>, <&pwm1_lpcg 2>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lppwm1>; clock-names = "per", "ipg","32k"; assigned-clocks = <&clk IMX_SC_R_PWM_1 IMX_SC_PM_CLK_PER>; assigned-clock-rates = <24000000> #pwm-cells = <2> power-domains = <&pd IMX_SC_R_PWM_1>; status = "okay"; }; pwm2_lsio: pwm@5d020000 { compatible = "fsl,imx8qxp-pwm", "fsl,imx27-pwm"; reg = <0x5d020000 0x1000>; clocks = <&pwm2_lpcg 0>, <&pwm2_lpcg 1>, <&pwm2_lpcg 2>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_lppwm2>; clock-names = "per", "ipg","32k"; assigned-clocks = <&clk IMX_SC_R_PWM_2 IMX_SC_PM_CLK_PER>; assigned-clock-rates = <24000000>; #pwm-cells = <2>; power-domains = <&pd IMX_SC_R_PWM_2>; status = "okay"; }; }; //#pwm-cells pwm 기반으로 사용하는 다른 driver에서 이를 사용 (backlight) https://www.kernel.org/doc/Documentation/devicetree/bindings/pwm/pwm.txt https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/pwm/pwm.txt };
2. PWM Driver 기본구조분석
PWM Driver 기본구조 및 sys filesystem 사용법
- PWM Driver (imx27)
- pwmchip_add()
- pwmchip_remove()
i.MX27 PWM Driver
- PWM 기반의 Driver (Back light)
pwm_request() 기반으로 구현
2.1 sys filesystem PWM-TEST
상위 imx27 Driver가 설정과 Clock 설정한 후 아래와 같이 설정가능하지만, 권한이 문제발생하여 아래와 같이 su 를 이용하여 root로 테스트
- PWM0 생성 및 기본제어방법
- period : 주기를 설정 ( ns 단위)
- duty_cycle: positive pulse width (ns 단위)
$ su
# id
uid=0(root) gid=0(root) groups=0(root),1007(log),3009(readproc) context=u:r:su:s0
$ echo 0 > /sys/class/pwm/pwmchip0/export // pwm0 생성됨
$ echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period
$ echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
$ echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
상위 설정은 1KHz의 주기를 가지고 Duty 즉, High Pulse는 반으로 설정
아래와 같이 50Hz 주기 설정 후 half duty로 변경 및 다양한 duty 테스트
//50Hz 20ms 주기 설정 $ echo 20000000 > /sys/class/pwm/pwmchip0/pwm0/period //10000us (10ms) (half) Positive Pulse $ echo 10000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle //1000 us (1ms) $ echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle //1250 us (1.25ms) $ echo 1250000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle //1500 us (1.5ms) $ echo 1500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle //1750 us (1.75ms) $ echo 1750000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle //2000 us (2.ms) $ echo 2000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
PWM 관련설정 사항
상위는 Android의 기본 shell에서 동작않아, 이를 해결하기 위해서 init.rc 에서 export 와 권한설정하기로 결정.
2.2 Android init.hardware.rc 문법 수정
Linux로 말하면, init script 이며, 이는 이부분 각 service와 초기화 관련부분을 담당
- init.rc
- init.%hardware%.rc
- Android Init 관련문법 복습
Init 문법을 보면 크게 Action 과 Service 와 command 나누어지며, 다음과 같이 동작한다.
//Action 기능 이며, trigger 와 command를 다양하게 지원 on <trigger> [&& <trigger>]* <command> <command> <command> //Service 기능이며 관련 option은 아래 링크 참조 service <name> <pathname> [ <argument> ]* <option> <option> ...
Android init 문법의 세부내용 Manual
- Android의 기본 init.rc 확인
기본 init.rc 위치 및 설정확인하였지만, 직접수정하지 않는 것이 좋을 것 같아 이부분은 그대로 유지
$ vi system/core/rootdir/init.rc // import /init.environ.rc import /init.usb.rc import /init.${ro.hardware}.rc import /vendor/etc/init/hw/init.${ro.hardware}.rc import /init.usb.configfs.rc import /init.${ro.zygote}.rc # Cgroups are mounted right before early-init using list from /etc/cgroups.json on early-init # Disable sysrq from keyboard write /proc/sys/kernel/sysrq 0 # Set the security context of /adb_keys if present. restorecon /adb_keys # Set the security context of /postinstall if present. restorecon /postinstall mkdir /acct/uid ......... $ cat out/target/product/mek_8q/root/init.rc
- i.MX8을 위한 init.hardware.rc 에 수정
각 hardware를 위한 init.rc 부분에 아래와 pwm관련설정부분을 추가를 해준다.
상위 문법을 보면 trigger 로 조건이 맞을 경우 command로 action이 되어진다.
$ vi ./device/fsl/imx8q/mek_8q/init.imx8qxp.rc ...... # jhlee /sys filesystem mount가 된 경우 실행 on property:sys.boot_completed=1 #jhlee for PWM1/2 root 권한으로 실행됨 chmod 0777 /sys/class/pwm/pwmchip0 chmod 0222 /sys/class/pwm/pwmchip0/export chmod 0222 /sys/class/pwm/pwmchip0/unexport chmod 0777 /sys/class/pwm/pwmchip1 chmod 0222 /sys/class/pwm/pwmchip1/export chmod 0222 /sys/class/pwm/pwmchip1/unexport # PWM1 50Hz 20ms / 10ms (half) write /sys/class/pwm/pwmchip0/export 0 write /sys/class/pwm/pwmchip0/pwm0/enable 1 write /sys/class/pwm/pwmchip0/pwm0/period 20000000 write /sys/class/pwm/pwmchip0/pwm0/duty_cycle 10000000 # PWM2 50Hz 20ms / 10ms (half) write /sys/class/pwm/pwmchip1/export 0 write /sys/class/pwm/pwmchip1/pwm0/enable 1 write /sys/class/pwm/pwmchip1/pwm0/period 20000000 write /sys/class/pwm/pwmchip1/pwm0/duty_cycle 10000000 chmod 0666 /sys/class/pwm/pwmchip0/pwm0/period chmod 0666 /sys/class/pwm/pwmchip0/pwm0/duty_cycle chmod 0666 /sys/class/pwm/pwmchip0/pwm0/enable chmod 0666 /sys/class/pwm/pwmchip1/pwm0/period chmod 0666 /sys/class/pwm/pwmchip1/pwm0/duty_cycle chmod 0666 /sys/class/pwm/pwmchip1/pwm0/enable # GPIO UART1_TX 21 write /sys/class/gpio/export 21 write /sys/class/gpio/gpio21/direction "out" write /sys/class/gpio/gpio21/value 1 # GPIO UART1_CTS_B 24 write /sys/class/gpio/export 24 write /sys/class/gpio/gpio24/direction "out" write /sys/class/gpio/gpio24/value 1 chmod 0666 /sys/class/gpio/export chmod 0666 /sys/class/gpio/unexport chmod 0666 /sys/class/gpio/gpio21/direction chmod 0666 /sys/class/gpio/gpio21/value chmod 0666 /sys/class/gpio/gpio24/direction chmod 0666 /sys/class/gpio/gpio24/value .... $ cat out/target/product/mek_8q/vendor/etc/init/hw/init.freescale.imx8qxp.rc // 빌드 후 실제 적용되어되었는지확인
init.rc script이 root기반으로 동작되기 때문에 초반에 chmod를 하는것은 의미가 없다
2.3 PWM ueventd.rc 문법 수정
처음 착각했던 것이 export를 값을 넣어주면, uevent가 발생하여 관련부분이 pwm이 생기면서 이 script를 이용하여 permission을 변경할 줄 알았다.
- ueventd.rc
- ueventd.%hardware%.rc
- uevend.rc script 기본이해
- ueventd.rc 설정
아래설정으로 하면 될 줄 알았는데, 실패했지만, 될 것이라고 생각되어 이곳에 기록하며 추후 재확인
$ vi ./device/fsl/imx8q/mek_8q/ueventd.freescale.rc # /sys file은 entry 5개 (주의) # /dev file은 entry 4개 # jhlee for pwmchip0 pwm0 /sys/devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0/pwm0 enable 0666 system system /sys/devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0/pwm0 period 0666 system system /sys/devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0/pwm0 duty_cycle 0666 system system /sys/devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0/pwm0 polarity 0666 system system # jhlee for pwmchip1 pwm0 /sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1/pwm0 enable 0666 system system /sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1/pwm0 period 0666 system system /sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1/pwm0 duty_cycle 0666 system system /sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1/pwm0 polarity 0666 system system # jhlee for pwm (0/1/2/3) /sys/class/pwm/pwmchip* export 0666 system system /sys/class/pwm/pwmchip* unexport 0666 system system /sys/class/pwm/pwmchip* enable 0666 system system /sys/class/pwm/pwmchip* period 0666 system system /sys/class/pwm/pwmchip* duty_cycle 0666 system system /sys/class/pwm/pwmchip* polarity 0666 system system
$ cat out/target/product/mek_8q/vendor/ueventd.rc // /sys file은 entry 5개 사용 주의
[ 5.133113] ueventd: /vendor/ueventd.rc: 44: /sys/ lines must have 5 entries
[ 5.140349] ueventd: /vendor/ueventd.rc: 45: /sys/ lines must have 5 entries
[ 5.147472] ueventd: /vendor/ueventd.rc: 46: /sys/ lines must have 5 entries
[ 5.154572] ueventd: /vendor/ueventd.rc: 47: /sys/ lines must have 5 entries
ueventd.rc pwm 과 gpio 관련예제
ueventd 별도정리 필요
- ueventd 의 동작의 이해와 udev 와 차이
- android ueventd Main 소스
- ueventd.rc Parser 소스
ParseConfig (ueventd.rc ) -> AddSingleLineParser->ParsePermissionsLine (각 sys or dev parsing 후 permision 설정 )
(sys 와 dev는 entry 갯수가 다르며, 이는 Cold boot를 위한 것이므로, Kernel에서 미리 설정되어야 한다)
- ueventd의 handler 소스
실제동작을 LOG_UEVENTS로 DEBUG 가능
- ueventd debug 방법
상위 ueventd 소스를 보면 LOG_UEVENTS 설정에 따라 LOG를 볼 수 있으며 이를 강제로 선언하여 Debug를 한다.
$ vi ./system/core/init/Android.mk ....... init_options += -DLOG_UEVENTS=1 \ -DSEPOLICY_VERSION=$(POLICYVERS) .......
ueventd의 selinux 설정
PWM의 sysfs의 구조
DEVICE_ATTR
DEVICE_ATTR_RW
DEVICE_ATTR_RO
DEVICE_ATTR_WO
device_attribute
- root 권한으로 shell 에서 pwm 위치 찾기
$ for i in /sys/class/pwm*/pwmchip*/pwm* ; do ls -l $i; cat $i; done total 0 -r--r--r-- 1 root root 4096 2021-01-20 07:16 capture -r--r--r-- 1 root root 4096 2021-01-20 07:16 consumers -rw-rw-rw- 1 root root 4096 2021-01-20 03:33 duty_cycle -rw-rw-rw- 1 root root 4096 2021-01-20 03:33 enable -r--r--r-- 1 root root 4096 2021-01-20 07:16 output_type -rw-rw-rw- 1 root root 4096 2021-01-20 03:33 period -rw-r--r-- 1 root root 4096 2021-01-20 07:16 polarity drwxr-xr-x 2 root root 0 2021-01-20 07:16 power -r--r--r-- 1 root root 4096 2021-01-20 07:16 suppliers -rw-r--r-- 1 root root 4096 2021-01-20 07:16 uevent cat: /sys/class/pwm/pwmchip0/pwm0: Is a directory total 0 -r--r--r-- 1 root root 4096 2021-01-20 07:17 capture -r--r--r-- 1 root root 4096 2021-01-20 07:17 consumers -rw-rw-rw- 1 root root 4096 2021-01-20 03:33 duty_cycle -rw-rw-rw- 1 root root 4096 2021-01-20 03:33 enable -r--r--r-- 1 root root 4096 2021-01-20 07:17 output_type -rw-rw-rw- 1 root root 4096 2021-01-20 03:33 period -rw-r--r-- 1 root root 4096 2021-01-20 07:17 polarity drwxr-xr-x 2 root root 0 2021-01-20 07:17 power -r--r--r-- 1 root root 4096 2021-01-20 07:17 suppliers -rw-r--r-- 1 root root 4096 2021-01-20 07:17 uevent cat: /sys/class/pwm/pwmchip1/pwm0: Is a directory $ ls -alh /sys/class/pwm/ //ueventd.*.rc에 추가하 위해서 정확한 PATH 알기 (아래는 강제로 권한변경된 상태) ... lrwxrwxrwx 1 root root 0 2020-12-30 06:06 pwmchip0 -> ../../devices/platform/bus@5d000000/5d010000.pwm/pwm/pwmchip0 lrwxrwxrwx 1 root root 0 2020-12-30 06:06 pwmchip1 -> ../../devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip1
2.4 SELinux
- i.MX8의 의 SElinux 문제발생 (동작안됨)
상위에서 write /sys/class/pwm/pwmchip0/export 0 할 경우 uevent가 발생할것이며, 아래와 같이 ls를 했을 경우 access 문제발생
mek_8q:/sys/class/pwm/pwmchip0 $ ls -alh drwxr-xr-x 3 root root 0 1970-01-01 00:00 .[ 175.487816] type=1400 audit(1609308473.916:27): avc: denied { getattr } for comm="ls" path="/sys/devices/platform/bus@5d000000/5d020000.pwm/pwm/pwmchip0/uevent" dev="sysfs" ino=34845 scontext=u:r:shell:s0 tcontext=u:object_r:sysfs:s0 tclass=file permissive=1
- BoardConfig.mk 관련수정
SElinux 를 허용모드(permissive) 강제로 변경후 별도의 추가 *.te를 할 필요가 없으므로 이를 간단히 해결
$ find . -name BoardConfig.mk // 기본위치파악 device/Vendor/ARCH/BoardName/BoardConfig.mk $ vi ./device/fsl/imx8q/mek_8q/BoardConfig.mk // i.MX8 관련수정 # NXP의 기본 Hardware 설정 # NXP default config BOARD_KERNEL_CMDLINE := init=/init androidboot.hardware=freescale firmware_class.path=/vendor/firmware loop.max_part=7 # # permissive 추가 BOARD_KERNEL_CMDLINE += androidboot.selinux=permissive
상위와 같이 permissive 로 변경할 경우, 상위와 같이 error는 발생하며, 경고는 하지만, 문제가 되지 않음
하지만, 이는 개발시에는 사용해야하면, 제품 출하시에는 반드시 관련부분을 수정해야한다.
Android SELinux (일반 Linux의 SELinux의 사용법과 좀 다름)
SELinux 관련부분 정리
3. Android SDK/NDK/PDK 구분
- SDK
Software Development Kit 로 순수 Application 입장이라고 생각하면 되겠으며, Java기반으로 Android Studio에서 제작가능하며, Google 제공하는 SDK에서 개발가능
Google에서 공식적인 제공하는 SDK 설치 한 후 이와 관련된 API 를 이용하여 사용자가 원할 경우 Custom으로 제작도 가능한 것으로 파악된다.
- NDK
Native Development Kit로 주로 C/C++로 기반으로 구현하며, JNI /HAL 을 제공하며, Library만 구성을 하여도 Application에서 이를 가져다가 사용가능하다.
Google에서 제공하는 NDK를 설치 한 후 이를 Build를 진행해야한다.
- PDK
Product(Platform) Development Kit로 SDK 와 NDK 의 동시에 사용할 경우를 말한다.
가장 쉬운예제가 JNI기능을 포함 SDK Program이며, 이는 PDK라고 불리운다.
상위에서 제공한 SDK 와 NDK를 설치한 후 이를 기반으로 작성가능하다.
NDK/PDK기반의 예제
상위를 간단히 분석을하면, Target의 /system/lib 에 본인이 구현한 library를 넣고 , 이를 기반으로 SDK에서 Class를 Loading하여 사용하면된다.
Android Studio를 이용하거나, ASOP에서 직접 빌드를 하면된다.
3.1 PWM PDK 작성방법
Android Studio에서 Native C++ 로 기반으로 PDK 구현할 경우 문제는 SELinux의 domain 이 untrusted_app로 생성되며, 이를 허용하지 않아
상위처럼 강제로 허용모드로 변경해야 했지만, Vendor입장에서 상위 untruested_app의 domain을 변경해서 사용해야 할 것 같다.
- Android Source 소스 수정
- ASOP_SETTING : ASOP에서 직접 수정(Access 문제) 후 이를 Build 후 관련 Image 생성
상위 2.2 init.hardware.rc 관련부분 수정 (init.xxxx.rc 상위 이름 참조 chmod로 변경)
상위 2.4 SELinux 의 Permissive , 즉 허용모드 변경 ( 접근허용으로 변경)
- Android Studio 기반으로 Native C++ 생성
- Android Studio-> New -> Native C++ 선택 후 기본 생성
- cpp -> CMakeLists.txt 변경 (기존 예제인 C++ 삭제)
- cpp -> GpioCtr.c / GpioCtr.h 추가
- cpp -> PWMCtr.c / PWMCtr.h 추가 (예제인 C++ 삭제)
- java -> com.example.jhlee -> GpioCtr.java
- java -> com.example.jhlee -> PWMCtr.java
- java -> com.example.jhlee -> MainActivity.java
- 관련 Sample 소스
3.3 기타사항
Android Application의 경우 AndroidManifest.xml 까지 추후에 봐야한다.
아래의 소스는 NDK 기반에서 /system/lib 에 넣고 SDK에서 이를 호출하여 동작하는 방식
Anroid Thing Native
Android Thing 상용화 무료가 아님
https://forum.odroid.com/viewtopic.php?f=178&t=37101
https://source.android.com/devices/architecture/kernel/reqs-interfaces?hl=ko
https://source.android.com/devices/architecture/kernel/reqs-interfaces?hl=ko
상위 /sys/class/pwm/pwmchip0 권한문제
PWM- Back light