导航

    全志在线开发者论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 话题
    • 在线文档
    • 社区主页
    1. 主页
    2. xfdr0805
    3. 帖子
    X
    • 资料
    • 关注 0
    • 粉丝 3
    • 我的积分 1476
    • 主题 9
    • 帖子 23
    • 最佳 4
    • 群组 0

    xfdr0805 发布的帖子

    • 回复: D1 LicheeRV Dock 移植RTL8723DS驱动

      @tigger 在 D1 LicheeRV Dock 移植RTL8723DS驱动 中说:

      ifconfig -a

      是不是有显示 wlan0 和 wlan1?

      wlan1 是不是可以作为热点用?

      大佬,研究一下airkiss或者smartconfig,我在8723ds测试 不太稳定,有时可以配网成功 有时不行,不知道怎么修改

      发布在 MR Series
      X
      xfdr0805
    • 回复: Windows/Linux 给 lvgl8 添加本地文件系统支持。

      @whycan lvgl本身就支持吧,只要在lv_config.h配置一下就可以用了
      *---------------------

      • 3rd party libraries
        --------------------/

      /*File system interfaces for common APIs
      To enable set a driver letter for that API/
      #define LV_USE_FS_STDIO '\0' /Uses fopen, fread, etc/
      //#define LV_FS_STDIO_PATH "/home/john/" /*Set the working directory. If commented it will be "./" */

      #define LV_USE_FS_POSIX 1 /Uses open, read, etc/
      #define CONFIG_LV_FS_POSIX_LETTER 'S' /Uses open, read, etc/
      //#define LV_FS_POSIX_PATH "/" /*Set the working directory. If commented it will be "./" */

      #define LV_USE_FS_WIN32 '\0' /Uses CreateFile, ReadFile, etc/
      //#define LV_FS_WIN32_PATH "C:\Users\john\" /*Set the working directory. If commented it will be ".\" */

      #define LV_USE_FS_FATFS '\0' /Uses f_open, f_read, etc/

      发布在 GUI
      X
      xfdr0805
    • 回复: 全志D1s可以申请样片了,本站网友开源原理图与PCB送三片D1s芯片(不能与其他网友作品雷同),还能送三片液晶显示屏

      @whycan
      谢晕哥 还是那个地址

      发布在 MR Series
      X
      xfdr0805
    • 回复: 全志D1s可以申请样片了,本站网友开源原理图与PCB送三片D1s芯片(不能与其他网友作品雷同),还能送三片液晶显示屏

      2021-11-15_223548.png 2021-11-15_223617.png

      F133_Board.pdf

      晕哥,现在还能申请芯片吗,验证OK后我会开源出来

      发布在 MR Series
      X
      xfdr0805
    • 动手让LVGL8带的Music-Demo音乐响起来(代码已上传)
      1. LVGL8 自带的有一个音乐播放器的Demo,效果不错,充分展示了LVGL8的弹性网格布局,动画等效果,来学习GUI是非常不错的,只是这个Demo并不能真正的播放音乐,但是已经把音乐播放的逻辑都给实现了,现在我们就动手给它注入灵魂----mpv
      2. 最初是用的sox这个号称音频界的瑞士军刀的工具,但是编写过程中碰到一个比较棘手的问题,那就是无法使用管道重定向输出(play本身不支持管道,只能借助sox),也就没办法获取播放进度,会造成进度条时间与实际播放时间有点误差,最后就放弃使用sox了

      2021-09-19_11-14.png

              if (pid == 0)
              {
                  LOG_D("child pid:%d\n", getpid());
                  char cmd[32];
                  prctl(PR_SET_PDEATHSIG, SIGKILL);
                  close(0);
                  dup2(pip[1], 1); //标准输出重定向到管道输出
                  close(pip[0]);
                  sprintf(buf, "./music/%s", _lv_demo_music_get_title(track_id));
                  sprintf(cmd, "--start=%d", _time, _lv_demo_music_get_track_length(track_id));
                  // execlp("ls", "ls", "./music", NULL);
                  // execlp("play", "play", "-p", buf, "trim", cmd, NULL);
                  // execlp("sox", "sox", buf, "-p", "|", "play", "-", "trim", cmd, NULL);
                  //最后知道怎么使用管道了,但是这是2个进程
                  // sox ./music/云非非\ -\ 邂逅.flac -t flac - | play -t flac - &
                  // sox ./music/云非非\ -\ 邂逅.flac -t flac - | play - &
                  // sox ./music/云非非\ -\ 邂逅.flac -p | play - &
                  return 0;
              } 
      
      1. 下边请出在后台默默工作的大佬MPV

        MPV播放器是什么?

        MPV是著名开源播放器mplayer和mplayer2的一个分支。
        mplayer则是这个地球上最强的播放器(没有之一),跨平台的特性使得windows、mac、linux上都可以见到它的身影,电脑、手机上很多播放器也是基于它开发的,由于mplayer不带界面,所以很多时候你都不知道是它在默默为你工作。
        并且mplayer播放视频时对于资源的消耗往往最少,所以你会发现在一台配置极差的电脑上播放高清电影,mplayer通常是最流畅的,使用快进时最能体现出差距,其他播放器已经画面卡死时,mplayer的画面可能只是感觉到掉帧而已。
        MPV播放器继承这些众多优良特性的同时,添加了内置于窗口的播放控制界面(OSC),对硬解的良好支持,以及其他额外特性。由于口碑很好,使得著名的mplayer前端:smplayer在不久前也添加了对MPV的支持,现在的smplayer你可以在mplayer和MPV2个核心之间切换使用。
        mpv官网的开发文档比较好,参考使用手册都可以使用起来

      2. 下边简单说一下过程
        a.首先要获取播放列表 播放列表里的字体是浪漫雅圆,使用freetype渲染的 。获取列表有2种方法
          方法1:
        
          int scan_music_list(char *_path)
          {
              char path[128];
              sprintf(path, "ls %s", _path);
              FILE *fp = popen(path, "r");
              if (ferror(fp))
              {
                  LOG_D("error\n");
              }
              char buf[128];
              while (!feof(fp))
              {
                  fgets(buf, sizeof(buf), fp);
                  strncpy(title_list[idx], buf, strlen(buf) - 1); //去掉文件名后的\n
                  get_music_info(title_list[idx], idx);
                  idx++;
                  usleep(1);
              }
              return idx;
          } 
          
        
         方法2:
        
         int list_dir(char *path, int depth)
         {
             DIR *dir;
             struct dirent *file;
             struct stat st;
             dir = opendir(path);
             if (!dir)
             {
                 LOG_D("open dir %s failed!", path);
                 return -1;
             }
             LOG_D("open dir %s ok!", path);
             while ((file = readdir(dir)) != NULL)
             {
                 if (strncmp(file->d_name, ".", 1) == 0 || strncmp(file->d_name, "..", 2) == 0)
                 {
                     continue;
                 }
                 strcpy(title_list[idx++], file->d_name);
                 if (stat(file->d_name, &st) >= 0 && S_ISDIR(st.st_mode) && depth <= 5)
                 {
                     list_dir(file->d_name, depth + 1);
                 }
             }
             closedir(dir);
             return 0;
         }      ```
        
        b.程序启动时创建一个子进程,一个线程获取播放进度,一个线程获取各种输入
          void lv_demo_music(void)
          {
              lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x343247), 0);
        
              music_num = scan_music_list(MUSIC_PATH);
              list = _lv_demo_music_list_create(lv_scr_act());
              ctrl = _lv_demo_music_main_create(lv_scr_act());
              pid = vfork();
              if (pid == 0)
              {
                  LOG_D("child pid:%d\n", getpid());
                  prctl(PR_SET_PDEATHSIG, SIGKILL);
                  execlp("mpv", "mpv", "--quiet", "--no-terminal", "--no-video", "--idle=yes", "--term-status-msg=", "--input-ipc-server=/tmp/mpvsocket", NULL);
                  LOG_D("child exit!\n");
                  return 0;
              }
              else if (pid > 0)
              {
                  LOG_D("parent pid:%d\n", getpid());
                  sleep(1);
                  close(0);
                  act.sa_handler = sigusr1;
                  sigfillset(&act.sa_mask);
                  act.sa_flags = SA_RESTART; /* don't fiddle with EINTR */
                  sigaction(SIGUSR1, &act, NULL);
                  addr.sun_family = AF_UNIX;
                  strcpy(addr.sun_path, "/tmp/mpvsocket");
                  fd_mpv = socket(AF_UNIX, SOCK_STREAM, 0);
                  if (fd_mpv == -1)
                  {
                      LOG_D("Create socket failed\n");
                  }
                  if (connect(fd_mpv, (struct sockaddr *)&addr, sizeof(addr)) == -1)
                  {
                      LOG_D("Cannot connect to socket %s\n", addr.sun_path);
                  }
                  if (pthread_create(&mthread, NULL, get_music_percent_pos, NULL) != 0)
                  {
                      LOG_D("pthread create error!\n");
                      return 0;
                  }
                  // LOG_D("get music pos pthread create ok!\n");
              }
              else
              {
                  LOG_D("fork error:\n");
              }
        
          #if LV_DEMO_MUSIC_AUTO_PLAY
              lv_timer_create(auto_step_cb, 1000, NULL);
          #endif
          }
        
          这里说明一下mpv里的参数
          "--quiet", //输出尽量少的信息
          "--no-terminal", //不接受终端输入
          "--no-video", //不需要视频
          "--idle=yes", //播放完不能出进程
          "--term-status-msg=", //状态信息不打印
          "--input-ipc-server=/tmp/mpvsocket"//使用sock方式与mpv通信
          这里使用的是mpv推荐的基于socket的JSON-based IPC protocol通信方式
        
        c. 一个线程启动时向mpv发送命令,然后监听事件就可以知道当前进度及状态
          void *get_music_percent_pos(void *arg)
          {
              // char cmd[] = "{\"command\": [ \"get_property\", \"playback-time\"] }\n";
              // char cmd[] = "{\"command\": [ \"get_property\", \"percent-pos\"] ,\"request_id\":2}\n";
              char cmd2[] = "{\"command\": [ \"observe_property\",2, \"percent-pos\"]}\n";
              char cmd1[] = "{\"command\": [  \"observe_property\",1,\"time-pos\"]}\n";
              char buf[512];
              cJSON *root;
              cJSON *event;
              cJSON *percent;
              write(fd_mpv, cmd1, strlen(cmd1));
              _msleep(100);
              write(fd_mpv, cmd2, strlen(cmd2));
              memset(buf, 0, sizeof(buf));
              while (1)
              {
        
                  if (read(fd_mpv, buf, sizeof(buf)) > 0)
                  {
                      //LOG_D("--->:%s\n", buf);
                      root = cJSON_Parse(buf);
                      if (root == NULL)
                      {
                          LOG_D("cJSON parse error!\n");
                          return;
                      }
                      // LOG_D("cJSON parse ok!\n");
                      if (cJSON_HasObjectItem(root, "event"))
                      {
        
                          event = cJSON_GetObjectItem(root, "event");
                          if (event != NULL)
                          {
                              if (strcmp(event->valuestring, "start-file") == 0)
                              {
                              }
                              else if (strcmp(event->valuestring, "metadata-update") == 0)
                              {
                              }
                              else if (strcmp(event->valuestring, "file-loaded") == 0)
                              {
                              }
                              else if (strcmp(event->valuestring, "property-change") == 0 && (cJSON_GetObjectItem(root, "id")->valueint == 1))
                              {
                                  percent = cJSON_GetObjectItem(root, "data");
                                  lv_label_set_text_fmt(time_obj, "%02d:%02d", (int)percent->valuedouble / 60, (int)percent->valuedouble % 60);
                                  LOG_D("time pos:%d\n", (int)percent->valuedouble);
                              }
                              else if (strcmp(event->valuestring, "property-change") == 0 && (cJSON_GetObjectItem(root, "id")->valueint == 2))
                              {
                                  percent = cJSON_GetObjectItem(root, "data");
                                  lv_slider_set_value(slider_obj, (int)percent->valuedouble, LV_ANIM_ON);
                                  LOG_D("percent pos:%d\n", (int)percent->valuedouble);
                              }
                              else if (strcmp(event->valuestring, "end-file") == 0)
                              {
                                  LOG_D("end-file\n");
                                  is_loaded = true;
                                  _lv_demo_music_album_next(true);
                              }
                              else if (strcmp(event->valuestring, "playback-restart") == 0)
                              {
                              }
                              else if (strcmp(event->valuestring, "idle") == 0)
                              {
                                  LOG_D("idle\n");
                              }
                          }
                      }
        
                      free(root);
                  }
                  //_msleep(250);
              }
              pthread_exit(NULL);
              LOG_D("pthread exit:\n");
          }
          这里通信都是采用JSON格式,使用了cJSON来解析送来的数据
              ``````
        
      3. 这些实现完成后,音乐播放器也就有了灵魂,就是一个真正的音乐播放器了,几乎支持所有音乐格式,我测试的常见的有wav,mp3,flac,ape,dts等
      4. 效果预览 (240*320) 项目位置:D1扩展板
      发布在 GUI
      X
      xfdr0805
    • 回复: 谁能提供一份XR829的固件 sdd_xr829.bin

      非常感谢!我下载试试

      发布在 MR Series
      X
      xfdr0805
    • 回复: 谁能提供一份XR829的固件 sdd_xr829.bin

      @dreamer
      我搜遍了,也没找到,Tina SDK 没能下载下来

      发布在 MR Series
      X
      xfdr0805
    • 回复: 给Neza-D1设计个扩展板

      扩展板上资源,除了外挂的声卡没调试好外,其它都OK了,既然不能注册声卡,那就应用层操作,反正D1上I2S配置好了,PCM5121通过I2C操作也很简单

      补上板子工程源文件 Kicad 5.99
      我发现Neza-D1开发板的这个引脚跟树莓派引脚兼容 😁
      今天才收到板子,焊接好后再补一张实物图片

      Neza-D1_expand_board.zip
      Neza-D1_expand_board.pdf
      2021-09-10 22-36-04屏幕截图.png
      2021-09-10 22-36-26屏幕截图.png

      发布在 MR Series
      X
      xfdr0805
    • Neza-D1开发板学习之SPI-LCD灯篇
      1. Neza-D1开发板芯片很强,但是没有引出RGB接口,板上引出了HDMI与MIPI接口,没引出RGB接口,手里的RGB接口的屏用不上了,扩展IO上有引出SPI1接口,看了一下尺寸,刚好可以放的下2.8”的SPI屏幕,正好手里有以前剩下的屏幕,就画了一块扩展板(可惜芯片是BGA封装,即使我能画出来,也没本事焊上啊!),驱动芯片是ili9341 4线SPI,又加了一个触摸芯片上去,如下图
        2021-09-10 22-23-50屏幕截图.png
      2. 设备树配置
          lcd_ili9341@0 {
      		#address-cells = <1>;
      		#size-cells = <1>;
      		compatible = "ilitek,ili9341";
      		reg = <0>;
      		spi-max-frequency = <32000000>;
      		rotation = <0>;
      		spi-cpol;
      		spi-cpha;
      		rgb;
      		fps = <30>;
      		buswidth = <8>;
      		txbuflen = <32768>;
      		reset-gpios = <&pcf8574 6 GPIO_ACTIVE_LOW>;
      		dc-gpios = <&pcf8574 7 GPIO_ACTIVE_LOW>;
      		/*backlight = <&backlight>;*/
      		led-gpios = <&pcf8574 5 GPIO_ACTIVE_HIGH>;
      		status = "okay";
          };
      
      1. 在内核打开small lcd support选项

        [] Staging drivers --->
        <
        > Support for small TFT LCD display modules --->3
        <*> FB driver for the ILI9341 LCD Controller

      2. 系统启动log

          [    2.670067] fbtft_of_value: buswidth = 8
          [    2.674512] fbtft_of_value: backlight = 39
          [    2.679097] fbtft_of_value: fps = 30
          [    2.683098] fbtft_of_value: txbuflen = 32768
          [    2.691259] GPT:Primary header thinks Alt. header is not at the end of the disk.
          [    2.699560] GPT:625184 != 7774207
          [    2.703265] GPT:Alternate GPT header not at the end of the disk.
          [    2.709981] GPT:625184 != 7774207
          [    2.713688] GPT: Use GNU Parted to correct GPT errors.
          [    2.719480]  mmcblk0: p1 p2 p3 p4
          [    2.987837] random: fast init done
          [    3.036258] graphics fb1: fb_ili9341 frame buffer, 240x320, 150 KiB video memory, 32 KiB buffer memory, fps=31, spi1.0 at 32 MHz
      
      1. 这里有一点需要注意,我们使用的GPIO是通过PCF8574扩展出来的,对IO读写操作时可能会导致休眠,因此不能在中断函数里使用,我们需要简单的修改一下驱动文件,用一个宏定义即可,如果不修改操作一次IO,就会出现一堆警告

        #define gpio_set_value gpio_set_value_cansleep

      2. 进系统里可以查看是否有对应设备

         # ls /dev/fb*
         /dev/fb0  /dev/fb1
         测试屏幕
         # cat /dev/urandom > /dev/fb1
         cat: write error: No space left on device
         清屏
         # cat /dev/zero > /dev/fb1
         cat: write error: No space left on device
         显示图片
         # fbv image1.jpg
        
      发布在 MR Series
      X
      xfdr0805
    • Neza-D1开发板学习之I2C-OLED篇
      1. Neza-D1开发板扩展IO上引出了I2C2,从原理图上看,已经接了PCF8574@38了,总线速度400K,我们的OLED也是接在这上边的,由于这屏幕比较小,显示不了多少东西,就不用FB方式了,直接在应用层操作OLED,所以设备树也不需要配置
        2021-09-10 22-07-43屏幕截图.png

      2. 在应用层操作就跟单片机操作是一样的了,这里为了方便操作屏幕,我分辨率移植u8g2这个库,我手里的哦了的是1.3"的,驱动IC是SHT1106,用1306也可以,只能显示不满屏,可能是基地址定义的不一样

      3. 我们不需要从OLED读取数据,所以只需要实现I2C写函数就可以,注意OLED模块上标的地址是0x78,这个是8位地址,这里使用的是7位地址,右移一位所以是0x3C

         unsigned char i2c_init()
         {
             const char *i2c_dev = "/dev/i2c-2";
             fd = open(i2c_dev, O_RDWR);
             if (fd < 0)
             {
                 printf("not have /dev/i2c-2 t\r\n");
                 fflush(stdout);
                 return -1;
             }
             return 0;
         }
         // I2C Addr 7bit
         unsigned char base_i2c_write(unsigned char device_addr, unsigned char *buff, int num)
         {
        
             struct i2c_rdwr_ioctl_data data;
             struct i2c_msg msgs_str[1];
             data.msgs = msgs_str;
             data.nmsgs = 1;
             data.msgs[0].len = num;
             data.msgs[0].addr = device_addr;
             data.msgs[0].flags = 0;
             data.msgs[0].buf = buff;
             ioctl(fd, I2C_RDWR, (unsigned long)&data);
         }
        
      4. 移植u8g2 非常简单,只需修改这下边这个函数里初始化位置和写数据位置就行,另外一个是延时,可以不用修改

         uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
         {
             /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
             static uint8_t buffer[128];
             static uint8_t buf_idx;
             uint8_t *data;
        
             switch (msg)
             {
             case U8X8_MSG_BYTE_INIT:
             {
                 /* add your custom code to init i2c subsystem */
                i2c_init; // I2C初始化
             }
             break;
        
             case U8X8_MSG_BYTE_START_TRANSFER:
             {
                 buf_idx = 0;
             }
             break;
        
             case U8X8_MSG_BYTE_SEND:
             {
                 data = (uint8_t *)arg_ptr;
        
                 while (arg_int > 0)
                 {
                     buffer[buf_idx++] = *data;
                     data++;
                     arg_int--;
                 }
             }
             break;
        
             case U8X8_MSG_BYTE_END_TRANSFER:
             {
                 //i2c写函数
                 if (base_i2c_write(OLED_ADDRESS, buffer, buf_idx) != 0)
                     return 0;
             }
             break;
        
             case U8X8_MSG_BYTE_SET_DC:
                 break;
        
             default:
                 return 0;
             }
        
             return 1;
         }
        
         uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
         {
             switch (msg)
             {
             case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
                 break;
             case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
                 break;
             case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
                 break;
             case U8X8_MSG_DELAY_I2C:      // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
                 break;                    // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
             case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
                 break;                    // arg_int=1: Input dir with pullup high for I2C clock pin
             case U8X8_MSG_GPIO_I2C_DATA:  // arg_int=0: Output low at I2C data pin
                 break;                    // arg_int=1: Input dir with pullup high for I2C data pin
             case U8X8_MSG_GPIO_MENU_SELECT:
                 u8x8_SetGPIOResult(u8x8, /* get menu select pin state */ 0);
                 break;
             case U8X8_MSG_GPIO_MENU_NEXT:
                 u8x8_SetGPIOResult(u8x8, /* get menu next pin state */ 0);
                 break;
             case U8X8_MSG_GPIO_MENU_PREV:
                 u8x8_SetGPIOResult(u8x8, /* get menu prev pin state */ 0);
                 break;
             case U8X8_MSG_GPIO_MENU_HOME:
                 u8x8_SetGPIOResult(u8x8, /* get menu home pin state */ 0);
                 break;
             default:
                 u8x8_SetGPIOResult(u8x8, 1); // default return value
                 break;
             }
             return 1;
         }
        
      5. 这就移植完了,带中文字库,可以直接显示中文,非常方便,做一个显示信息的小玩意儿还是非常方便的,下边编译一下传到开发板里,可以看到显示成功(图片)

      6. 最后附上完整工程供参考
        neza_d1_u8g2_oled.7z

      发布在 MR Series
      X
      xfdr0805
    • Neza-D1开发板学习之红外发送与接收篇
      1. D1芯片本身有硬件ir-tx ir-rx,但在开发板上通过扩展IO引出的只有IR-RX,IR-TX用不了,被I2C2占用了,只有用IO来发射红外信号了
        2021-09-10 22-02-07屏幕截图.png
      2. 设备对配置
        发射引脚,使用的是GPIO 需要在内核打开GPIO IR Bit Banging
         ir_send {
      		compatible  = "gpio-ir-tx";
      		gpios = <&pio 3 22 GPIO_ACTIVE_HIGH>; /* PD22 */
      		status = "okay";
      	};
          接收引脚
          &s_cir0 {
              pinctrl-names = "default", "sleep";
              pinctrl-0 = <&s_cir0_pins_a>;
              pinctrl-1 = <&s_cir0_pins_b>;
              linux,rc-map-name = "rc-tbs-nec";
              status = "okay";
          };
      

      下边是系统log

      [    1.719737] i2c /dev entries driver
      [    1.723748] IR NEC protocol handler initialized
      [    1.728825] IR RC5(x/sz) protocol handler initialized
      [    1.735217] rc rc0: GPIO IR Bit Banging Transmitter as /devices/platform/soc@3000000/soc@3000000:ir_send/rc/rc0
      [    1.746722] rc rc0: lirc_dev: driver gpio-ir-tx registered at minor = 0, no receiver, raw IR transmitter
      [    1.758445] sunxi_ir_startup: get ir protocol failed
      [    1.758467] (NULL device *): deviceless supply  not found, using dummy regulator
      [    1.772394] Registered IR keymap rc_map_sunxi
      [    1.777404] rc rc1: sunxi-ir as /devices/platform/soc@3000000/7040000.s_cir/rc/rc1
      [    1.786130] rc rc1: lirc_dev: driver sunxi-rc-recv registered at minor = 1, raw IR receiver, no transmitter
      [    1.797263] input: sunxi-ir as /devices/platform/soc@3000000/7040000.s_cir/rc/rc1/s_cir_rx
      
      1. 查看系统 /dev下的设备

         # ls /dev/lirc*
         /dev/lirc1  /dev/lirc1  /dev/lircd
        
      2. 此时查看/dev/input目录下,会有如下显示:

         # evtest 
         No device specified, trying to scan all of /dev/input/event*
         Available devices:
         /dev/input/event0:      sunxi-keyboard
         /dev/input/event1:      soc@3000000:rotary
         /dev/input/event2:      sunxi-ir
         /dev/input/event3:      audiocodec sunxi Audio Jack
         /dev/input/event4:      soc@3000000:gpio_keys
         /dev/input/event5:      ns2009_ts
        

        此时如果用evtest测试按键是没有任何反应的,因为keymap我们没有修改成自己用的遥控器,当然就不上报事件了,但不影响后续操作

      3. 我们可以用lirc里的工具去测试硬件是否OK,测试之前要先修改默认配置文件,不修改的话,同样没反应

         # vi /etc/lirc/lirc_options.conf 
         driver          = default
         device          = /dev/lric1
         修改这2行就可以,里边driver默认是uinput,device默认是auto
         再次测试就有反应了
         # mode2 -m -d /dev/lirc1
         Using driver default on device /dev/lirc1
         Trying device: /dev/lirc1
         Using device: /dev/lirc1
         Warning: Running as root.
            9043     4402      626      497      656      499
             624      499      656      499      624      499
             656      499      624      499      624      531
             624     1630      619     1624      655     1624
             624     1624      624     1634      646     1624
             624     1624      655     1624      593     1656
             624      501      654     1624      593      534
             652     1624      624      499      625     1624
             656      504      619      499      655     1625
             624      499      656     1625      593      531
             624     1633      648      498      624     1624
             624    40035  
            9060     2184      624   143451-pulse   483450-space
        

        从这结果上可以明显的看出这些数值代表脉冲宽度,单位是us

      4. 使用irrecod -f -d /dev/lirc1 --disable-namespace来录制配置文件
        录制完成后放到 /etc/lric/liricd.conf.d/下边
        !注意,这里录制的结果不准确,需要借助上边的命令来获取每一个按键的值,这里只是借用一下配置文件的格式,里边的数字是右对齐
        示例:

         # Please take the time to finish this file as described in
         # https://sourceforge.net/p/lirc-remotes/wiki/Checklist/
         # and make it available to others by sending it to
         # <lirc@bartelmus.de>
         #
         # This config file was automatically generated
         # using lirc-0.10.1(default) on Thu Jan  1 01:37:06 1970
         # Command line used: -f -d /dev/lirc1 --disable-namespace
         # Kernel version (uname -r): 5.10.19
         #
         # Remote name (as of config file): elac
         # Brand of remote device, the thing you hold in your hand:
         # Remote device model nr:
         # Remote device info url:
         # Does remote device has a bundled capture device e. g., a
         #     usb dongle? :
         # For bundled USB devices: usb vendor id, product id
         #     and device string (use dmesg or lsusb):
         # Type of device controlled
         #     (TV, VCR, Audio, DVD, Satellite, Cable, HTPC, ...) :
         # Device(s) controlled by this remote:
        
         begin remote
        
         name  elac
         flags RAW_CODES|CONST_LENGTH
         eps            30
         aeps          100
        
         gap          108533
        
             begin raw_codes
        
                 name Power
                9043     4403      623      531      593      531
                 624      531      593      531      624      531
                 593      531      624      531      593      536
                 594     1680      592     1656      593     1656
                 625     1655      593     1666      582     1656
                 624     1656      593     1655      625      530
                 593      534      621      530      593     1656
                 624     1624      624      531      593      530
                 624      531      595     1655      623     1655
                 593     1656      593      530      624      531
                 593     1664      616     1656      593     1656
                 593
        
                 name BT
                9041     4407      622      531      593      531
                 593      562      593      531      593      531
                 625      533      596      525      624      530
                 593     1656      624     1656      593     1655
                 593     1664      616     1655      593     1656
                 593     1656      624     1658      591      530
                 624     1656      593      531      624      531
                 593      531      593      531      624     1661
                 587      530      624     1656      593      531
                 593     1687      593     1656      601     1648
                 624     1656      593      531      593     1656
                 624
        
             name Vol+
                9013     4437      592      530      593      562
                 593      531      624      531      593      531
                 594      565      589      530      593      531
                 624     1656      593     1656      624     1665
                 590     1651      591     1656      624     1655
                 593     1656      593     1667      613      531
                 593     1656      624     1656      593      531
                 593      562      595      528      593     1656
                 624      531      593     1656      624      531
                 593      530      593     1659      621     1655
                 593     1656      593      562      593     1656
                 593
                 
             name Vol-
                9044     4436      592      531      624      531
                 593      533      622      530      593      531
                 593      531      624      531      593      530
                 624     1656      593     1661      595     1679
                 593     1655      593     1656      624     1656
                 593     1667      582     1659      620      530
                 593     1656      624     1656      600      524
                 624     1656      593      531      593      531
                 624      531      593     1656      624      531
                 598      530      620     1654      593      531
                 624     1625      624     1656      593     1666
                 614
        
             name Pre
                9048     4403      592      562      593      530
                 593      562      593      530      593      531
                 624      531      593      531      624      531
                 593     1661      593     1680      592     1656
                 593     1656      624     1656      603     1650
                 588     1656      623     1656      593     1656
                 624     1662      587     1655      593      531
                 624      531      593      531      624     1656
                 593      531      631      524      593      530
                 593      562      593     1656      593     1656
                 624     1663      586      530      624     1624
                 624
                 .
                 .
                 .
                 .
                 .
             end raw_codes
        
         end remote
        
      5. 接下来使用irw来验证刚才录制的是否正确

         # irw
         lircd-0.10.1[432]: Notice: accepted new client on /var/run/lirc/lircd
         lircd-0.10.1[432]: Info: [lirc] protocol is enabled
         0000000000000001 00 Power elac
         0000000000000002 00 BT elac
         0000000000000003 00 Vol+ elac
         0000000000000004 00 Vol- elac
         0000000000000008 00 Ana1 elac
         000000000000000a 00 Opt1 elac
         000000000000000b 00 Opt2 elac
        
      6. 然后在/etc/lirc/目录下创建lircrc配置文件或~/.lircrc
        格式如下

         begin
                 prog = irexec
                 button = Power
                 repeat = 0
                 config = echo "power"
         end
         begin
                 prog = irexec
                 button = Vol+
                 repeat = 1
                 config = amixer -M -c 0 sset 'Headphone',0 1%+ > /dev/null
         end
         begin
                 prog = irexec
                 button = Vol-
                 repeat = 1
                 config = amixer -M -c 0 sset 'Headphone',0 1%- > /dev/null
         end
        

        保存

      7. 最后就是使用irexec来进行各种操作了,无需编程,到这里可以自由发挥了,想要集成到代码里也很简单,看下图

         # irexec 
         lircd-0.10.1[448]: Notice: accepted new client on /var/run/lirc/lircd
         lircd-0.10.1[448]: Info: [lirc] protocol is enabled
         
         volume up click
         Simple mixer control 'Headphone',0
         Capabilities: pvolume pvolume-joined pswitch
         Playback channels: Front Left - Front Right
         Limits: Playback 0 - 63
         Mono:
         Front Left: Playback 47 [54%] [-16.00dB] [on]
         Front Right: Playback 47 [54%] [-16.00dB] [on]
        
         volume down click
         Simple mixer control 'Headphone',0
         Capabilities: pvolume pvolume-joined pswitch
         Playback channels: Front Left - Front Right
         Limits: Playback 0 - 63
         Mono:
         Front Left: Playback 45 [50%] [-18.00dB] [on]
         Front Right: Playback 45 [50%] [-18.00dB] [on]
        
      8. LIRC处理流程

                +--------+         +-------------+                     +--------+
                |        |         | Linux input |                     | Appli- |
         --->---| kernel |---->----| layer       |---------->----------| cation |
                |        |         |             |  /dev/input/eventX  |        |
                +--------+         +-------------+                     +--------+
        
        
                +--------+         +-------------+
                |        |         | Linux input |
         --->---| kernel |---->----| layer       |
                |        |         |             |
                +--------+         +-------------+
                                            |
                                            v
                                            |
                                            |                           +--------+
                                    +-------------+                     | Appli- |
                                    |    lirc     |---------->----------| cation |-+
                                    |             |     lirc socket     |        | |
                                    +-------------+                     +--------+ |-+
                                                                            |        | |
                                                                            +--------+ |
                                                                            |        |
                                                                            +--------+
        
                +--------+         +-------------+                     +--------+
                |        |         |             |                     | Appli- |
         --->---| kernel |---->----|    lirc     |---------->----------| cation |-+
                |        |         |             |     lirc socket     |        | |
                +--------+         +-------------+                     +--------+ |-+
                                                                            |        | |
                                                                            +--------+ |
                                                                            |        |
                                                                            +--------+
        
      9. 通过socket使用lirc,不需要引入任何文件,可以方便的集成到代码里,就是上述第三种方式

        struct sigaction act;
        char buf[128];
        struct sockaddr_un addr;
        typedef struct
        {
            char addr[32];
            char code[8];
            char type[16];
            char name[16];
        } IRW_DATA;
        IRW_DATA irw_data;
        act.sa_handler = sigusr1;
        sigfillset(&act.sa_mask);
        act.sa_flags = SA_RESTART; /* don't fiddle with EINTR */
        sigaction(SIGUSR1, &act, NULL);
        addr.sun_family = AF_UNIX;
        strcpy(addr.sun_path, "/var/run/lirc/lircd");
        fd_lircd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
        if (fd_lircd == -1)
        {
            printf("Create socket failed\n");
        }
        if (connect(fd_lircd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
        {
            printf("Cannot connect to socket %s\n", addr.sun_path);
        }
        while (1)
        {
            // lircd
            if (read(fd_lircd, buf, 128) > 0)
            {
                LOG_D("%s\n", buf);
                char *p = strtok(buf, " ");
                int i = 0;
                while (p)
                {
                    // LOG_D("%s\n", p);
                    if (i == 0)
                        strcpy(irw_data.addr, p);
                    else if (i == 1)
                        strcpy(irw_data.code, p);
                    else if (i == 2)
                        strcpy(irw_data.type, p);
                    else if (i == 3)
                        strcpy(irw_data.name, p);
                    p = strtok(NULL, " ");
                    i++;
                }
                LOG_D("%s\n", irw_data.type);
                switch ((uint8_t)strtol(irw_data.addr, NULL, 10))
                {
                case Vol_up:
                    rotary_encoder_handler(&u8g2, -1);
                    break;
                case Vol_down:
                    rotary_encoder_handler(&u8g2, 1);
                    break;
                case Play:
                    rotary_encoder_button_handler(&u8g2);
                    break;
                case Bt:
                    printf("BT button\n");
                    break;
                }
            }
        }
        
      10. 下边开始向外发射IR信号,发射就使用之前录制的配置文件

        irsend SEND_ONCE elac power
        
      发布在 MR Series
      X
      xfdr0805
    • Neza-D1开发板学习之按键和旋转编码器篇
      1. Neza-D1开发板上只引出一个按键,是使用的LRADC检检测按键的,想使用更多按键,可以使用板子上通过PCF8574扩展出来的IO,我画的扩展板使用了四个按键,分别为PP0,PP1,PP2,PP4

        KEY.png

      2. 设备树配置如下 内核需要勾选 Polled input device skeleton

         gpio_keys {
             compatible = "gpio-keys";
             pinctrl-names = "default";
             /*pinctrl-0 = <&key_pins>;*/
             #address-cells = <1>;
             #size-cells = <0>;
             autorepeat;
             button@0 {
                 label = "Key volume up";
                 linux,code = <KEY_VOLUMEUP>;
                 gpios = <&pcf8574 0 GPIO_ACTIVE_LOW>; /* PP0 */
             };
        
             button@1 {
                 label = "Key volume down";
                 linux,code = <KEY_VOLUMEDOWN>;
                 gpios = <&pcf8574 1 GPIO_ACTIVE_LOW>; /* PP1 */
             };
             
             button@2 {
                 label = "Key back";
                 linux,code = <KEY_BACK>;
                 gpios = <&pcf8574 2 GPIO_ACTIVE_LOW>; /* PP2 */
             };
        
             button@3 {
                 label = "Key enter";
                 linux,code = <KEY_ENTER>;
                 gpios = <&pcf8574 4 GPIO_ACTIVE_LOW>; /* PP4 */
             };
        
         };
        
      3. 编码器接在D1的PD14 PD15 设备树如下
        注意需要内核勾选<*> Polled GPIO Decoder Input driver

         rotary {
             compatible = "rotary-encoder";
             pinctrl-names = "default";
             /*pinctrl-0 = <&rotary_pins>;*/
             gpios = <&pio 3 14 GPIO_ACTIVE_LOW>, <&pio 3 15 GPIO_ACTIVE_LOW>; /* PD14, PD15 */
             linux,axis = <0>; /* REL_X */
             rotary-encoder,encoding = "gray";
             rotary-encoder,relative-axis;
         };
        

        然后在内核勾选

      4. 系统启动会有如下log

         [    0.111735] input: sunxi-keyboard as /devices/virtual/input/input0  这是板载的那个LRADC 按键
         [    1.668976] rotary-encoder soc@3000000:rotary: gray 这是旋转编码器
         [    1.675145] input: soc@3000000:rotary as /devices/platform/soc@3000000/soc@3000000:rotary/input/input1
         [    3.178668] input: soc@3000000:gpio_keys as /devices/platform/soc@3000000/soc@3000000:gpio_keys/input/input5 这是扩展出来的那4个按键
        
      5. 查看系统里已注册的输入设备,用这个比较清楚,ls /dev/input也可以

         # evtest 
         No device specified, trying to scan all of /dev/input/event*
         Available devices:
         /dev/input/event0:      sunxi-keyboard
         /dev/input/event1:      soc@3000000:rotary
         /dev/input/event2:      sunxi-ir
         /dev/input/event3:      audiocodec sunxi Audio Jack
         /dev/input/event4:      soc@3000000:gpio_keys
         /dev/input/event5:      ns2009_ts
        
      6. 可以使用evtest或hexdump来测试按键是否正常了

      7. 在代码使用就比较简单了

         #include <errno.h>
         #include <global.h>
         #include <linux/fcntl.h>
         #include <linux/input.h>
         #include <signal.h>
         #include <stdio.h> //-std=c99  -std=gnu99
         #include <stdlib.h>
         #include <string.h>
         #include <sys/types.h>
         #include <unistd.h>
        
         #define msleep(t) usleep((t)*1000)
         FILE *fp;
         int32_t fd_key;
         int32_t fd_encoder;
         struct input_event t;
         int main(int argc, char const *argv[])
         {
        
             fd_key = open("/dev/input/event1", O_RDONLY | O_NONBLOCK);
             if (fd_key < 0)
             {
                 fprintf(stderr, "error:can not open /dev/input/event1\n");
                 return -1;
             }
             fd_encoder = open("/dev/input/event4", O_RDONLY | O_NONBLOCK);
             if (fd_encoder < 0)
             {
                 fprintf(stderr, "error:can not open /dev/input/event4\n");
                 return -1;
             }
        
             while (1)
             {
        
                 // rotary encoder
                 if (read(fd_encoder, &t, sizeof(t)) == sizeof(t))
                 {
        
                     if (t.type == EV_REL)
                     {
                         LOG_D("ROTARY DIR: %d->%s\n", t.value, t.value == 1 ? "CC" : "CW");
                         rotary_encoder_handler(&u8g2, t.value);
                     }
                 }
                 // key
                 if (read(fd_key, &t, sizeof(t)) == sizeof(t))
                 {
                     if (t.type == EV_KEY)
                     {
                         switch (t.code)
                         {
                         case KEY_OK:
                             LOG_D("KEY_ENTER %s \n", t.value ? "Pressed" : "Released");
                             if (t.value == 0)
                                 rotary_encoder_button_handler(&u8g2);
                             break;
                         case KEY_SELECT:
                             LOG_D("KEY_SELECT %s \n", t.value ? "Pressed" : "Released");
                             break;
                         case KEY_VOLUMEUP:
                             LOG_D("KEY_VOLUMEUP %s \n", t.value ? "Pressed" : "Released");
                             if (t.value == 0)
                             {
                                 rotary_encoder_handler(&u8g2, -1);
                             }
        
                             break;
                         case KEY_VOLUMEDOWN:
                             LOG_D("KEY_VOLUMEDOWN %s \n", t.value ? "Pressed" : "Released");
                             if (t.value == 0)
                             {
                                 rotary_encoder_handler(&u8g2, 1);
                             }
                             break;
                         default:
                             break;
                         }
                     }
                 }
                 usleep(1);
             }
        
             return 0;
         }
        
      发布在 MR Series
      X
      xfdr0805
    • Neza-D1开发板学习之点灯篇
      1. 板子到手先来点个灯那是少不了的,先确定LED接在哪个引脚上,查看原理图,发现LED的座位号是U13,原来不是普通的LED,是一颗单总线的WS2812灯珠,这颗LED是接在PC0引脚上的,引脚标有LEDC-DO,是接在了LED控制器上,驱动官方已经做好了,我们直接用就可以

      2. 下边废话不多说,来看一下系统启动过程,系统已经把驱动给加载好了

         [    2.100847] sunxi_led_probe()1715 - start
         [    2.105375] sunxi_get_str_of_property()1560 - failed to get the string of propname led_regulator!
         [    2.115306] sunxi_register_led_classdev()1448 - led_classdev start
         [    2.126681] sunxi_led_probe()1820 - finish
        
      3. 来查看一下LED子系统下的灯

         # ls /sys/class/leds/
         blink         sunxi_led11g  sunxi_led3b   sunxi_led5r   sunxi_led8g
         sunxi_led0b   sunxi_led11r  sunxi_led3g   sunxi_led6b   sunxi_led8r
         sunxi_led0g   sunxi_led1b   sunxi_led3r   sunxi_led6g   sunxi_led9b
         sunxi_led0r   sunxi_led1g   sunxi_led4b   sunxi_led6r   sunxi_led9g
         sunxi_led10b  sunxi_led1r   sunxi_led4g   sunxi_led7b   sunxi_led9r
         sunxi_led10g  sunxi_led2b   sunxi_led4r   sunxi_led7g
         sunxi_led10r  sunxi_led2g   sunxi_led5b   sunxi_led7r
         sunxi_led11b  sunxi_led2r   sunxi_led5g   sunxi_led8b
        

        这里出现了很多LED,设备树默认是12个,这样子是不是很熟悉了,我们板子上的LED就是led0

         # ls /sys/class/leds/sunxi_led0b/
         brightness            power                 uevent
         device                subsystem             waiting_for_supplier
         max_brightness        trigger
        

        先来个红色的呼吸灯

         # echo heartbeat > /sys/class/leds/sunxi_led0r/trigger 
        

        再来个蓝色1秒闪烁一次

         # echo timer > /sys/class/leds/sunxi_led0b/trigger
        

        这灯真是亮瞎眼啊,查看亮度

         # cat  /sys/class/leds/sunxi_led0b/brightness 
         255
        

        调到50,这下好了

         # echo 50 > /sys/class/leds/sunxi_led0b/brightness
        

        把灯关掉

          # echo none > /sys/class/leds/sunxi_led0b/trigger
        

        查看支持哪些触发方式

         # cat  /sys/class/leds/sunxi_led0b/trigger 
         none rc-feedback rfkill-any rfkill-none kbd-scrolllock kbd-numlock kbd-capslock kbd-kanalock kbd-shiftlock kbd-altgrlock kbd-ctrllock kbd-altlock kbd-shiftllock kbd-shiftrlock kbd-ctrlllock kbd-ctrlrlock mmc0 mmc1 timer oneshot [mtd] nand-disk heartbeat backlight gpio cpu cpu0 activity default-on transient netdev pattern audio-mute audio-micmute
        
      4. 当然以上的操作不是操作的GPIO,而是使用的LED子系统,下边是用GPIO操作LED,这里的LED是在扩展板上引出的,引脚是通过PCF8574扩展出来的,具体可以看看D1原理图

      5. 使用SYSFS方式操作GPIO,在操作前先查看一下系统里未使用的GPIO,这里以PD18 BL—PWM为例

        # ls /sys/class/gpio/
        export        gpiochip0     gpiochip2020  unexport
        # PD18 = 32*3+18=114
        # echo 114 > export 
        

        执行成功 目录下会出现gpio114,查看一下内容,可以看到里边有direction,value

        # ls gpio114 
        active_low            edge                  uevent
        device                power                 value
        direction             subsystem             waiting_for_supplier
        

        接下来设置方向

        # echo out > gpio114/direction 
        

        输出高电平

        # echo 1 > gpio114/value
        

        输出低电平

        # echo 0 > gpio114/value
        

        不用的话执行

        # echo 114 > unexport
        

        查看一下,已经没有那个引脚导出的目录了

        # ls
        export        gpiochip0     gpiochip2020  unexport
        
      6. 使用GPIOD操作GPIO,先查询一下系统GPIO情况

         # gpiodetect 
         gpiochip0 [2000000.pinctrl] (224 lines)
         gpiochip1 [pcf8574] (8 lines)
         # gpioinfo gpiochip0 | grep -v unused | grep -v kernel
         gpiochip0 - 224 lines:
                 line   0:      unnamed      "sysfs"   input  active-high [used]
                 line   1:      unnamed      "sysfs"   input  active-high [used]
                 line   5:      unnamed      "sysfs"   input  active-high [used]
                 line  34:      unnamed  "interrupt"   input  active-high [used]
                 line 110:      unnamed "soc@3000000:rotary" input active-low [used]
                 line 111:      unnamed "soc@3000000:rotary" input active-low [used]
                 line 115:      unnamed  "usb1-vbus"  output  active-high [used]
                 line 116:      unnamed    "otg_det"   input  active-high [used]
                 line 117:      unnamed     "otg_id"   input  active-high [used]
                 line 118:      unnamed "soc@3000000:ir_send" output active-high [used]
                 line 144:      unnamed    "phy-rst"  output  active-high [used]
                 line 166:      unnamed         "cd"   input  active-high [used]
         # gpioinfo gpiochip1
         gpiochip1 - 8 lines:
                 line   0:      unnamed "Key volume up" input active-low [used]
                 line   1:      unnamed "Key volume down" input active-low [used]
                 line   2:      unnamed   "Key back"   input   active-low [used]
                 line   3:      unnamed      "blink"  output   active-low [used]
                 line   4:      unnamed  "Key enter"   input   active-low [used]
                 line   5:      unnamed        "led"  output  active-high [used]
                 line   6:      unnamed      "reset"  output   active-low [used]
                 line   7:      unnamed         "dc"  output   active-low [used]
        

        同样使用上边那个未使用的引脚为例 PD18 BL-PWM
        输出高电平

         # gpioset gpiochip0 114=1
        

        输出低电平

         # gpioset gpiochip0 114=0
        

        读取引脚电平

         # gpioget gpiochip0 114
         1
        

        就这么简单

      7. 以上操作还都未涉及到代码,下边开始用代码操作GPIO,代码仅供参考

        SYSFS方式

         #include <stdio.h>
         #include <stdlib.h>
         #include <string.h>
         #include <unistd.h>
         int main(void)
         {
             FILE *p = NULL;
             int i = 0;
             p = fopen("/sys/class/gpio/export", "w");
             fprintf(p, "%d", 38);
             fclose(p);
             p = fopen("/sys/class/gpio/gpio38/direction", "w");
             fprintf(p, "out");
             fclose(p);
             for (i = 0; i < 100; i++)
             {
                 p = fopen("/sys/class/gpio/gpio38/value", "w");
                 fprintf(p, "%d", 1);
                 sleep(1);
                 fclose(p);
                 p = fopen("/sys/class/gpio/gpio38/value", "w");
                 fprintf(p, "%d", 0);
                 sleep(1);
                 fclose(p);
             }
             p = fopen("/sys/class/gpio/unexport", "w");
             fprintf(p, "%d", 38);
             fclose(p);
             return 0;
         }
        

        GPIOD方式

         #include "gpiod/gpiod.h"
         #include <linux/fcntl.h>
         #include <signal.h>
         #include <stdio.h> -std=c99  -std=gnu99
         #include <stdlib.h>
         #include <string.h>
         #include <sys/time.h>
         #include <unistd.h>
         #define LED_PIN 148     PD8 32*3+18
         #define msleep(t) usleep((t)*1000)
        
         struct gpiod_chip *chip;
         struct gpiod_line *line;
         
         void _timer_handler(int n)
         {
             num++;
             gpiod_line_set_value(line, num % 2);
         }
         int main(int argc, char const *argv[])
         {
             struct gpiod_line_request_config config;
             int req;
             /* 1.打开 GPIO 控制器 */
             chip = gpiod_chip_open("/dev/gpiochip0");
             if (!chip)
                 return -1;
             /* 2.获取指定引脚 */
             line = gpiod_chip_get_line(chip, LED_PIN);
             if (!line)
             {
                 gpiod_chip_close(chip);
                 return -1;
             }
             /* 3.配置引脚输出  */
              req = gpiod_line_request_output(line, "blink", 0);
              if (req)
              {
                  fprintf(stderr, "gpio line request error.\n");
                  return -1;
              }
             signal(SIGALRM, _timer_handler);
             struct itimerval itv;
             itv.it_value.tv_sec = 1;
             itv.it_value.tv_usec = 1000; 
             itv.it_interval.tv_sec = 1;
             itv.it_interval.tv_usec = 0;
             setitimer(ITIMER_REAL, &itv, NULL);
             while (1)
             {
                 
             }
        
             return 0;
         }
        
      8. 到此点灯结束,感谢观看!

      发布在 MR Series
      X
      xfdr0805
    • 谁能提供一份XR829的固件 sdd_xr829.bin
      # modprobe xr829.ko 
      [  100.391586] ======== XRADIO WIFI OPEN ========
      [  100.398517] [XRADIO] Driver Label:XR_V02.16.84_P2P_HT40_01.31   
      [  100.405334] [XRADIO] Allocated hw_priv @ 000000009b3877eb
      [  100.413152] sunxi-rfkill soc@3000000:rfkill@0: bus_index: 1
      [  100.429430] sunxi-rfkill soc@3000000:rfkill@0: wlan power on success
      [  100.636545] [XRADIO] Detect SDIO card 1
      [  100.651420] sunxi-mmc 4021000.sdmmc: sdc set ios:clk 0Hz bm PP pm UP vdd 21 width 1 timing LEGACY(SDR12) dt B
      [  100.673356] sunxi-mmc 4021000.sdmmc: no vqmmc,Check if there is regulator
      [  100.693300] sunxi-mmc 4021000.sdmmc: sdc set ios:clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
      [  100.717916] sunxi-mmc 4021000.sdmmc: sdc set ios:clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
      [  100.737273] sunxi-mmc 4021000.sdmmc: sdc set ios:clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
      [  100.762531] sunxi-mmc 4021000.sdmmc: sdc set ios:clk 400000Hz bm PP pm ON vdd 21 width 1 timing SD-HS(SDR25) dt B
      [  100.774088] sunxi-mmc 4021000.sdmmc: sdc set ios:clk 50000000Hz bm PP pm ON vdd 21 width 1 timing SD-HS(SDR25) dt B
      [  100.786258] sunxi-mmc 4021000.sdmmc: sdc set ios:clk 50000000Hz bm PP pm ON vdd 21 width 4 timing SD-HS(SDR25) dt B
      [  100.798775] mmc1: new high speed SDIO card at address 0001
      [  100.806454] [SBUS] XRadio Device:sdio clk=50000000
      [  100.872826] [XRADIO] XRADIO_HW_REV 1.0 detected.
      [  100.881593] xradio_wlan mmc1:0001:1: Direct firmware load for sdd_xr829.bin failed with error -2
      [  100.891437] [XRADIO_ERR] xradio_parse_sdd: can't load sdd file sdd_xr829.bin.
      [  100.899420] [XRADIO_ERR] xradio_load_firmware failed(-2).
      [  100.906159] sunxi-rfkill soc@3000000:rfkill@0: wlan power off success
      

      使用的是韦老师的【极简操作】使用builroot 2021一键编译生成D1 nezha 系统镜像!
      目前编译完驱动,加载时找不到sdd_xr829.bin buildroot里好像没有,谁能提供一份XR829的固件 sdd_xr829.bin,谢谢!

      发布在 MR Series
      X
      xfdr0805
    • 回复: Fedora on Allwinner D1 Nezha Board

      @tigger Neza -D1 越来越好玩啦!

      发布在 MR Series
      X
      xfdr0805
    • D1 配置I2S2正常 但是外挂PCM512X出错

      不外接codec 使用I2S2 我测试是正常的 虽然pcm512x有硬件模式 但这样不太方便 如果外挂codec 启动时会出错 但从图片上看pcm512x配置应该是正常的 也能通信 但是I2S却没输出了
      07821803-5FC8-4978-BB80-476C624FAE36.png 38EBBD56-604E-45C6-89E8-00C2E35DAD34.png ADD392F7-280A-408C-B752-4050DC35E845.png

      发布在 MR Series
      X
      xfdr0805
    • 给Neza-D1设计个扩展板

      扩展板资源:
      1.一路IR-RX(DHT22)
      2.一路IR-TX
      3.一路IIC OLED 1.3“
      4.一路RotaryRncoder
      5.一路SPI LCD 240x320 2.4”
      6.一路触摸IC TS2009
      7.一路I2S + PCM5121 384KHz DAC
      8.四路按键
      2021-09-01_233513.png 2021-09-01_233458.png Neza-D1_expand_board.pdf

      板子已经JLC打样,调试完成后全部放上来

      发布在 MR Series
      X
      xfdr0805
    • 回复: 【极简操作】使用builroot 2021一键编译生成D1 nezha 系统镜像!

      大佬 板载wifi xr829支持了吗

      发布在 MR Series
      X
      xfdr0805
    • 回复: 【极简操作】使用builroot 2021一键编译生成D1 nezha 系统镜像!

      @haoxuan-cui 我的编译出来也是这么大 系统可以正常使用 可能是编译了qt进去了才比较大

      发布在 MR Series
      X
      xfdr0805
    • 回复: 【极简操作】使用builroot 2021一键编译生成D1 nezha 系统镜像!

      @spring 还是NFS方便,挂载上都不用传输了,直接使用

      发布在 MR Series
      X
      xfdr0805
    • 回复: 【走过路过的朋友不要错过】全志在线(bbs.aw-ol.com)做项目赠送哪吒开发板活动

      @whycan 这么一捋 第一条就不满足了😄whycan.com贴算不?

      发布在 MR Series
      X
      xfdr0805
    • 回复: 【走过路过的朋友不要错过】全志在线(bbs.aw-ol.com)做项目赠送哪吒开发板活动

      @whycan 想报名音乐播放器 可惜看到时已经错过日期了 不知道还能报名不?

      发布在 MR Series
      X
      xfdr0805
    • 1 / 1