2023年12月22日 星期五

ASUS Tinker Board 2S - Android 11- Change I2C speed (clock-frequency)

  ASUS Tinker Board 2S - Android 11- Change I2C speed (clock-frequency)

這方法只適用於自行編譯Android 11 source code方式

如要使用官網發佈之Android 11 Image file, 請使用官網論壇之方法.

https://tinker-board.asus.com/forum/index.php?/topic/15458-i2c-speed/&tab=comments#comment-16920


Step 1:

 建議先從乾淨下載的 Android 11 source code 進行測試

下載方式如下

  https://snoopymemory.blogspot.com/2023/10/asus-tinker-board-2s-1.html

 repo sync 完成後, 進行下列修改

Step 2:

 開啟 /kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi

 取得 i2c6 及 i2c7 之記憶體位址, 如下  





Step 3:

  開啟 /kernel/arch/arm64/boot/dts/rockchip/rk3399-tinker-board-2.dtsi

 將原來的內容 修改為 

 clock-frequency = <400000>

   傳輸速率為 400 kbit/s

 clock-frequency = <100000>;  

   傳輸速率為 100 kbit/s


Step 3:

 從 docker-builder-run.sh 開始編譯程式

 https://snoopymemory.blogspot.com/2023/10/asus-tinker-board-2s-4.html


Step 4:

  使用 balenaEtcher 將 /rockdev/Image-WW_Tinker_Board_2/WW_Tinker_Board_2-raw.img 

  燒錄到SD Card中.

Step 5:

  使用燒錄好的 SD Card 於ASUS Tinker Board 2S開機
  使用內建的 Tinker Config APP 把 i2c6 及 i2c7 開啟

Step 6:

開啟windwos power shell

> adb devices

  220198250600582

> adb -s 220198250600582 shell

/* ff150000 在step 1 rk3399.dtsi 中查詢到的 */

$ od -bc /proc/device-tree/i2c\@ff150000/clock-frequency

0000000 000 006 032 200
         \0 006 032 200
0000004

$ od -bc /proc/device-tree/i2c\@ff160000/clock-frequency
0000000 000 001 206 240
         \0 001 206 240
0000004

I2C6 
/sys/devices/platform/ff150000.i2c/of_node/clock-frequency
BitRateHz dword: hex as 0x00061a80 => decimal 400000  400kHz
I2C7
/sys/devices/platform/ff160000.i2c/of_node/clock-frequency
BitRateHz dword: hex as 0x000186a0 => decimal 100000  100kHz  



下面是實際測試

先對 I2C6 讀取



再對 I2C7 讀取












2023年11月20日 星期一

關於 FT260Q 開發版 DS_UMFT260EV1A操作方法(Windows)

 關於 FT260Q 開發版 DS_UMFT260EV1A I2C操作方法(Windows)


FT260Q 對I2C的指令做的比較單純, 大部份FT260Q已包裹起來(類似Linux 的 I2C_dev )

如果想要自己下達I2C每一個步驟的指令, 可以考慮使用CH341A

CH341A優點是可以完全自行控制, 缺點是程式碼要增加百倍.

(CH341也有提供簡單的包裹式指令集)



SCL : GPIO0

SDL : GPIO1

開發版上面還多掛了一顆 EEPROM AT24C02D

Device Address: 0x50

如果要取消這顆EEPROM , 把開發版之 JP8 切斷




開發版 DS_UMFT260EV1A
https://ftdichip.com/products/umft260ev1a/

EEPROM AT24C02D
https://www.microchip.com/en-us/product/at24c02d

FT260Q 
https://ftdichip.com/products/ft260q/


LibFT260
Application Note AN_395 User Guide for LibFT260 
https://www.ftdichip.com/Support/Documents/AppNotes/AN_395_User_Guide_for_LibFT260.pdf
這是原廠提供的一組函式庫,可以將指量傳輸給FT260Q
https://ftdichip.com/software-examples/
最下面那個沒有說明的 Libft260
https://ftdichip.com/wp-content/uploads/2022/10/LibFT260-v1.1.6.zip

解壓縮後
\LibFT260-v1.1.6\imports\LibFT260\inc\LibFT260.h
\LibFT260-v1.1.6\imports\LibFT260\lib\i386\LibFT260.lib, LibFT260.dll 

範例程式 (須要使用 Visual Studio )
\LibFT260-v1.1.6\samples\I2C

原始範例程式可以使用 Device Address  0x50 對EEPROM AT24C02D直接讀寫.

下面是直接修改對EEPROM AT24C256 直接讀寫. 

// Open Device
    FT260_HANDLE mhandle1 = INVALID_HANDLE_VALUE;
    FT260_STATUS ftStatus = FT260_OK;
    DWORD devNum = 0;
    FT260_CreateDeviceList(&devNum);

    // #define VID 0x0403  #define PID 0x6030
    ftStatus = FT260_OpenByVidPid(VID ,PID, 0, &mhandle1) ;
    printf("FT260_OpenByVidPid = %d\n",ftStatus );

    ftStatus = FT260_I2CMaster_Init(mhandle1, 100);


// (5)Read EEPROM 
 unsigned long len;
 DWORD writeLength = 0;
 DWORD readLength = 0;
 char dataw[10], datar[10];

 gI2CAddr = 0x51;
 writeLength = 0;
 dataw[0] = 0x00;
 dataw[1] = 0x00;
 FT260_I2CMaster_Write(mhandle1, gI2CAddr, FT260_I2C_START, &dataw, 2, &writeLength);
 writeLength = 0;
 len = 8;
 FT260_I2CMaster_Read(mhandle1, gI2CAddr, (FT260_I2C_FLAG)(FT260_I2C_REPEATED_START | FT260_I2C_STOP),
     datar, len, &readLength, 5000);



// (6)Write EEPROM 

 unsigned long len;
 DWORD writeLength = 0;
 char data[10];
 char addr;
 FT260_STATUS ftStatusW1, ftStatusW2 = FT260_OK;

 gI2CAddr = 0x51;
 writeLength = 0;
 data[0] = 0x00; // Data Address MSB
 data[1] = 0x00; // Data Address LSB
 
 ftStatusW1 = FT260_I2CMaster_Write(mhandle1, gI2CAddr, FT260_I2C_START, &addr, 2, &writeLength);
 data[0] = 0xAA;  // Write Data 
 data[1] = 0x22;
 data[2] = 0x33;
 data[3] = 0x44;
 data[4] = 0x55;
 data[5] = 0x66;
 data[6] = 0x77;
 data[7] = 0x88;
 ftStatusW2 = FT260_I2CMaster_Write(mhandle1, gI2CAddr, FT260_I2C_STOP, &data[0], 8, &writeLength);

上圖和規格書的要求很類似




比較難的是  I2C_FLAG 的選擇
建議是各種指令都下一次, 使用分析儀來解析其不同之處

enum FT260_I2C_FLAG
{
FT260_I2C_NONE  = 0,
FT260_I2C_START = 0x02,
FT260_I2C_REPEATED_START = 0x03,
FT260_I2C_STOP  = 0x04,
FT260_I2C_START_AND_STOP = 0x06
};

相關解釋可以查看AN_395_User_Guide_for_LibFT260.pdf
Page 20  4.2 I2C Master Functions







2023年11月9日 星期四

ASUS Tinker Board 2S Debian 使用實體電源開關

當  Tinker Board 2S Debian中按了系統左上角的 shotdown後ㄉ

Tinker Board 2S除了拔電源開關讓其啟動, 

只能使用實體電源開關讓其再次啟動,

 

 注意

  這個會和 ASUS Tinker Board 2S 關閉睡眠功能 那邊有點衝突

  當 suspend 被關時, 會出現

  GDBus.Error:org.freedesktop.DBus.Error.AccessDenied: Permission denied

  所以要安裝實體電源開關,   不要加入 



Debian 系統設定


2.無段開關


3.

因PCB 沒有印刷, 所以要注意方向, 很容易搞錯.
MASKROM 是用來燒錄UBOOT或EMMC時使用

4.








ASUS Tinker Board 2S Debian 安裝 Teamviewer Host

 下載 https://www.teamviewer.com/hk/download/linux/

 TeamViewer Host  Debian arm64-64bit


$ sudo dpkg -i teamviewer-host_15.47.3_arm64.deb

ASUS Tinker Board 2S 設定 GPIO(Using the sysfs Interface)

 ASUS Tinker Board 2S 設定 GPIO(Using the sysfs Interface)


https://tinker-board.asus.com/forum/index.php?/topic/14984-gpio/


方法一:

 Using the sysfs Interface

就是直接對 Linux File System 的 /sys/class/gpio/ 文字檔進行讀寫

方法二:

使用 ASUS 提供的  GPIO WiringPi for C library

https://github.com/TinkerBoard/TinkerBoard/wiki/User-Guide#sample-code-for-tinker-board-2-series

http://dlcdnet.asus.com/pub/ASUS/mb/Linux/Tinker_Board_2GB/GPIO_API_for_C.ZIP


方法三:

使用 ASUS API Programming方式(只有使用範例, 無原始碼)
https://tinker-board.asus.com/tw/documentation/ter.html#api/

方法一說明:

1. 先到wiki 查詢 2S GPIO pin對應到 Linux Debian之Device Path

  (Tinker Board 2S 每一個GPIO Pin 對應到Linux GPIO Index)

  GPIO Config Table for Tinker Board 2 series:

  https://github.com/TinkerBoard/TinkerBoard/wiki/User-Guide#gpio-config-table-for-tinker-board-2-series






  

 例如本次要試驗的是 Tinker Board 2S GPIO pin-18 

  對應到 Debian之Device Path是 GPIO: /sys/class/gpio/gpio87

  


2. 參考網站

  GPIO Programming: Using the sysfs Interface

    https://www.ics.com/blog/gpio-programming-using-sysfs-interface

  風火輪對 /sys/class/gpio 之解釋文

    https://wiki.youyeetoo.cn/tinker/page/DebianSystem/User_GPIO

3. 設定

  $ sudo bluefish /boot/config.txt

    下面這一行 GPIO pin-18 為 spi5 不可以打開

    #intf:spi5=off

4. 指令

    > Device Path是 GPIO: /sys/class/gpio/gpio87

    $ sudo su

    $ cd /sys/class/gpio

    $ echo 87 >/sys/class/gpio/export

    $ ls /sys/class/gpio/gpio87/

    $ echo out >/sys/class/gpio/gpio87/direction

    $ echo 0 >/sys/class/gpio/gpio87/value

     > 電錶量測 Tinker Board 2S GPIO pin-18 會是 0 

    $ echo 1 >/sys/class/gpio/gpio87/valu

     > 電錶量測 Tinker Board 2S  GPIO pin-18 會是 3.3v


5. C/C++ Example
   How to Control GPIO Hardware from C or C++
   https://www.ics.com/blog/how-control-gpio-hardware-c-or-c
   https://github.com/tranter/blogs/tree/master/gpio/part5


2023年11月8日 星期三

ASUS Tinker Board 2S - Debian I2C TCA9539

 

TI TCA9539

16-bit 1.65- to 5.5-V I2C/SMBus I/O expander with interrupt, reset & config registers


IO-EXPANDER-EVM: I2C and SMBus IO Expander Evaluation Module






1. 修改  /boot/config.txt 內容
intf:i2c6=on    /* 原始前面有個 # 要去除, 把 off 改為on */

2. 連接 I2C
  SCL: IO-EXPANDER J8 SCL
  SDA: IO-EXPANDER J8 SDA
  GND: IO-EXPANDER J7 GND
  VCC: IO-EXPANDER J9 VCC

3.Device Address
PS: IO Expander EVM User's Guide (Rev. A) 這一片是共用PCB.
TCA6424A  0100010 0x22 
TCA9539     1110111 0x77 



  


GPIO設定, 主要是在Registers 6 和7


 但這片 IO Expander EVM 另外拉了幾條線用於顯示LED燈
 可以直接改用J13 來測試GPIO


第一個是 Device Address 
    i2cmsg.addr  = nDevAddr;
第二個是  Registers 6或7
第三個就是 GPIO Pin 0到N 的 GPIO ON/OFF


4. Linux IOCTL 範例程式


#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <err.h>
#include <errno.h>
#include <string.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define DEFAULT_I2C_BUS      "/dev/i2c-6"
// 0100010 0x22 TCA6424A
// 1110111 0x77 TCA9539
#define DEFAULT_TCA9539_ADDR 0x77

int TCA9539_write( int nFile, unsigned int nDevAddr, unsigned int nRegConfig,
                  unsigned char *pBuf, unsigned char nLen)
{
  struct i2c_rdwr_ioctl_data msg_rdwr;
  struct i2c_msg i2cmsg;
  int nRecLen;
  unsigned char sI2cBuf[0xFF];
  unsigned char *pI2cBuf = &sI2cBuf[0];

  msg_rdwr.msgs = &i2cmsg;
  msg_rdwr.nmsgs = 1;

  pI2cBuf[0] = (unsigned char)nRegConfig;
  pI2cBuf[1] = pBuf[0];
  i2cmsg.addr  = nDevAddr;
  i2cmsg.flags = 0;  // Write
  i2cmsg.len   = 2;
  i2cmsg.buf   = pI2cBuf;
  if( ( nRecLen = ioctl( nFile, I2C_RDWR, &msg_rdwr)) < 0)
  {
   perror("W5A-ioctl()");
   fprintf( stderr,"W5B-ioctl %d\n%s\n", nRecLen, strerror(errno));
   return -1;
  }
  else
   return nRecLen;
}

int TCA9539_read( int nFile, unsigned int nDevAddr, unsigned int nRegConfig,
                  unsigned char *pBuf, unsigned char nLen)
{
  struct i2c_rdwr_ioctl_data msg_rdwr;
  struct i2c_msg i2cmsg[2];
  unsigned char sAdsBuf[3];
  unsigned char *pAdsBuf = &sAdsBuf[0];
  int nRecLen;

  msg_rdwr.msgs = i2cmsg;
  msg_rdwr.nmsgs = 2;

  pAdsBuf[0] = (unsigned char)nRegConfig;
  i2cmsg[0].addr  = nDevAddr;
  i2cmsg[0].flags = 0;  // Write
  i2cmsg[0].len   = 1;
  i2cmsg[0].buf   = pAdsBuf; 
    
  i2cmsg[1].addr  = nDevAddr;
  i2cmsg[1].flags = I2C_M_RD;  // read data, from slave to master
  i2cmsg[1].len   = nLen;
  i2cmsg[1].buf   = pBuf;

  if( ( nRecLen = ioctl( nFile, I2C_RDWR, &msg_rdwr))<0)
  {
   perror("R5-TCA9539_read ioctl failed");
   fprintf(stderr,"R6-TCA9539_read ioctl returned %d\n", nRecLen);
   return -1;
  }
  else
  {
   return nRecLen;
  } 
}

int main(void)
{
 int nDevAddr = DEFAULT_TCA9539_ADDR;
 int nFile, nWriteLen, nReadLen, nRecLen; 
 int nRc, nRegConfig;
 const char *pDevice = DEFAULT_I2C_BUS; //"/dev/i2c-6";
 unsigned char sBuf[0x10], sStrBuf[0x10];
 unsigned char *pBuf= &sBuf[0];
 unsigned long nFuncs;
 

 printf("Hello! This is a test prgoram.\n");
 nFile = open( pDevice, O_RDWR);
 if( nFile < 0)
  err( errno, "O1-Tried to open '%s'", pDevice);
 else
  printf( "\nO2-Open dev i2c-6 success.\n");

 if( ioctl( nFile, I2C_FUNCS, &nFuncs) < 0)
 {
  perror("W5A-ioctl()");
  fprintf(stderr, "Error: Could not get the adapter functionality matrix: %s\n",
  strerror(errno));
  close( nFile);
  exit(0);
 }
 ioctl( nFile, I2C_TIMEOUT,2); // TIMEOUT
 ioctl( nFile, I2C_RETRIES,1); // retry count
    
 nRc = ioctl( nFile, I2C_SLAVE, nDevAddr);
 if( nRc < 0)
 {
  err(errno, "O3-Tried to set device address '0x%02x'", nDevAddr);
  exit(0);
 }
 else
 {
  printf("O4-Dev i2c-6 Set Address 0x50 success.\n");
 }

 
 // https://www.ti.com/product/zh-tw/TCA9539 // Pull High
 // Table 7. Registers 6 And 7 (Configuration Registers)
 nDevAddr = DEFAULT_TCA9539_ADDR;
 nRegConfig = 0x06; // Registers 6 Configuration
 pBuf[0] = 0x00;  // Set GPIO Pin-0 to Pin-7 all Pull Low
 nWriteLen = 1;
 nRecLen = TCA9539_write( nFile, nDevAddr, nRegConfig, pBuf, nWriteLen);
 if( nRecLen < 0)
 {
  printf( "W3A-TCA9539_write failed.\n");
  exit(0);
 }
 else
 {
  fprintf( stderr, "W6-Set gpio pin0-7: 0x%02x\n", pBuf[0]);
 } 
 nRegConfig = 0x07;  // Registers 7 Configuration
 pBuf[0] = 0x00;  // Set GPIO Pin-10 to Pin-17 all Pull Low
 nWriteLen = 1;
 nRecLen = TCA9539_write( nFile, nDevAddr, nRegConfig, pBuf, nWriteLen);
 if( nRecLen < 0)
 {
  printf( "W3A-TCA9539_write failed.\n");
  exit(0);
 }
 else
 {
  fprintf( stderr, "W7-Set gpio pin10-17: 0x%02x\n", pBuf[0]);
 } 

 // Read Process
 nDevAddr = DEFAULT_TCA9539_ADDR;
 nRegConfig = 0x06; // Registers 6 Configuration
 pBuf[0] = 0xFF;    // Read GPIO Pin-0 to Pin-7 
 nReadLen = 1;
 nRecLen = TCA9539_read( nFile, nDevAddr, nRegConfig, pBuf, nReadLen);
 if( nRecLen < 0)
 {
  printf("R1-TCA9539_read failed.\n");
  exit(1);
 }
 else
 {
  fprintf( stderr, "W6-Get gpio pin0-7: 0x%02x\n", pBuf[0]);
 }   
 nRegConfig = 0x07; // Registers 7 Configuration
 pBuf[0] = 0xFF;    // Read GPIO Pin-10 to Pin-17 
 nReadLen = 1;
 nRecLen = TCA9539_read( nFile, nDevAddr, nRegConfig, pBuf, nReadLen);
 if( nRecLen < 0)
 {
  printf("R1-TCA9539_read failed.\n");
  exit(1);
 }
 else
 {
  fprintf( stderr, "W6-Get gpio pin10-17: 0x%02x\n", pBuf[0]);
 }   
 close( nFile);
 return 0;
}




5.

















ASUS Tinker Board 2S 關閉睡眠功能

 Disable Suspend and Hibernation

 $ sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target

 $ reboot

 $ systemctl status sleep.target suspend.target hibernate.target hybrid-sleep.target

 $ sudo vim /etc/systemd/logind.conf 

   [Login] 

   HandleLidSwitch=ignore 

   HandleLidSwitchDocked=ignore 



 Enable Suspend and Hibernation

 $ sudo systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target