精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

使用系統IO和標準IO的基本原理

CHANBAEK ? 來源:非典型技術宅 ? 作者:非典型技術宅 ? 2023-11-24 09:48 ? 次閱讀

系統 IO 和標準 IO

系統 IO 一般指的是 Linux/Unix 系統調用中關于 I/O 操作的統稱,其中包括 open、read、write、close 等操作。

與系統 IO 對應還有標準 IO,標準 IO 是 ISO 標準中 C 語言標準定義的 IO 訪問接口,例如 fprintf/fgets 等 C 語言標準中定義的文件訪問接口。

在 Linux 系統中 open/read/write 等函數的底層實現是通過系統調用訪問的,在 STM32 的裸機中沒有操作系統,更沒有這些系統調用。

但是我們可以用一種其他的方式去實現這些系統 IO,而不需要操作系統。

半主機模式重寫文件訪問接口

這個方法其實就是利用半主機模式,去重寫系統庫中關于半主機接口中關于文件訪問接口的底層 "弱定義"

這個聽上去好像挺陌生的,其實很多人都使用過,就是最簡單的 printf 重定向。

在 GCC 重定向 printf 到串口使用了如下代碼:

int _write(int fd, char * ptr, int len)
{
  HAL_UART_Transmit(&huart1, (uint8_t *) ptr, len, HAL_MAX_DELAY);
  return len;
}

這個就是在半主機模式下重寫了 write 函數的底層接口,當系統調用 printf 函數時最終會調到 _write 函數向串口寫入數據。

ARM 關于主機模式的文檔 中,Direct semihosting C library function dependencies 一節提供了可重寫的系統 IO 的底層函數。

圖片

通過重寫上述列表中的函數,即可通過調用 C 庫 系統 IO 訪問。

構建文件系統

在上面介紹使用系統 IO 的基本原理:通過重寫 _open/_write/_read 等接口,即可通過 open/write/read 接口訪問。

但是以上只提供了一系列系統接口,并將其與標準 IO 綁定,可以使用 open/fopen 等函數進行訪問,但是具體訪問的數據依舊需要自己進行實現。

在這次測試中我選用了 LittleFS 作為文件系統,使用 RAM 中預分配的全局變量作為存儲介質,構建了一個基于內存的文件系統。(開發板沒有 Flash 先用 RAM 代替了。。。)

其 _open 函數如下:

// 文件描述符列表,不包括標準輸入輸出, 最大 fd 為 FS_FILE_MAX + 3
lfs_file_t *g_file_list[FS_FILE_MAX] = {0};

int _open(const char *name, int flags)
{
  int i;
  int i_flags = 0;

  if ((flags & O_CREAT)  == O_CREAT)  i_flags |= LFS_O_CREAT;
  if ((flags & O_RDONLY) == O_RDONLY) i_flags |= LFS_O_RDONLY;
  if ((flags & O_WRONLY) == O_WRONLY) i_flags |= LFS_O_WRONLY;
  if ((flags & O_RDWR)   == O_RDWR)   i_flags |= LFS_O_RDWR;

  for (i = 0; i < FS_FILE_MAX; i++)
  {
    if (g_file_list[i] == NULL)
    {
      g_file_list[i] = malloc(sizeof(lfs_file_t));
      lfs_file_open(&g_lfs, g_file_list[i], name, i_flags);
      return i + 3;
    }
  }
  
  return -1;
}

其基本邏輯是將 open 傳入的參數轉換為 lfs_file_open 使用的參數,傳入 lfs_file_oen, 然后分配一個空閑的文件描述符作為返回值。

在 _read 和 _write 接口中對文件描述符進行判斷,當文件描述符為 0/1/2 時將數據重定向到串口,否則從文件中讀寫數據。代碼如下:

int _write(int fd, char *pBuffer, int size)
{
  int res = 0;

  if (fd == 1 || fd ==2)
  {
    HAL_UART_Transmit(&huart3, (uint8_t *)pBuffer, size, size);
  }
  else
  {
    res = lfs_file_write(&g_lfs, g_file_list[fd], pBuffer, size);
  }

  return res;
}

完成以上步驟后,便可以在程序中使用 open/read/write 等接口訪問文件系統了,測試程序如下:

fs_init();

  write(STDOUT_FILENO, "system init ...n", 17);
  
  mkdir("/data", 0755);
  fd = open("/data/ascii.txt", O_CREAT|O_WRONLY);
  
  for (ch = 32; ch < 126; ch++)
  {
    write(fd, &ch, 1);
  }
  close(fd);

  fd = open("/data/ascii.txt", O_RDONLY);
  while (1)
  {
    char buff[16];
    int res = read(fd, buff, 16);
    if (res < 0)
    {
      close(fd);
      break; 
    }

    printf("system tick: %"PRIu32"n", HAL_GetTick());
    printf("read file data:%.*sn", 16, buff);
    HAL_Delay(500);
  }

程序下載燒錄后,使用串口工具查看到以下數據:

圖片

移植的用途

關于在 STM32 中使用系統 IO 的嘗試,主要是為了在 STM32 上移植一些 Linux 下的第三方庫。

他們很多都不可避免的使用了文件 IO 和 Posix 線程接口,對于 Posix 線程的接口在 FreeRTOS 中有提供,但是系統 IO 卻沒有找到什么合適的方案,于是有了這樣的一種嘗試。

現在好像已經有了更好的方案而不用去移植,不過使用這種方式的好處是以較少的代碼可以將系統 IO 和標準 IO 進行關聯。

關于半主機模式

最后提一下半主機模式:這個實質上是提供了一個在調試時訪問主機數據的方法:

通過觸發 SVC 指令,在 R0 寄存器中傳入需要的系統調用 ID, 在 R1 寄存器中傳入參數結構體的指針。

通過調試器,可以在主機接受到對應的系統調用,并進行相應的處理。

該測試程序整理好后,上傳到文末 閱讀原文 的 github 鏈接,或者發送 “測試代碼” 到公眾號后臺獲取源碼。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8496

    瀏覽量

    150834
  • Linux
    +關注

    關注

    87

    文章

    11225

    瀏覽量

    208917
  • 操作系統
    +關注

    關注

    37

    文章

    6737

    瀏覽量

    123190
  • STM32
    +關注

    關注

    2266

    文章

    10871

    瀏覽量

    354789
  • IO口
    +關注

    關注

    3

    文章

    169

    瀏覽量

    23994
收藏 人收藏

    評論

    相關推薦

    標準IO的介紹

    標準IO由ANSI C標準定義在ANSI C標準中還定義了c庫,用于提供一系列的函數標準IO就是
    發表于 04-26 09:53

    GPIO基本原理與寄存器配置基礎信息

    GPIO基本原理與寄存器配置基礎信息STM32F103ZET6,一共有7組IO口,每組IO口有16個IOUSART:(Universal Synchronous/Asynchronous
    發表于 08-16 07:56

    文件IO標準IO有何區別

    嵌入式Linux開發系統開發之《一節課搞懂文件IO標準IO
    發表于 11-04 06:42

    搞懂文件IO標準IO

    嵌入式Linux開發系統開發之《一節課搞懂文件IO標準IO
    發表于 12-16 08:18

    電源濾波器的基本原理和常用標準

    電源濾波器是電力電子技術中常用的一種裝置,用于去除電源中的噪聲和高頻干擾,保證電子設備的正常運行。下面小編帶大家來了解一下電源濾波器的基本原理和常用標準。一、電源濾波器的基本原理電源濾波器是一種電路
    發表于 04-14 15:21

    AVR的IO結構分析與操作

    AVR的IO是真正雙向IO結構,由于大部分網友都是從標準51轉過來的,受標準51的準雙向IO和布爾操作概念影響,沒能掌握AVR的
    發表于 11-01 01:21 ?23次下載

    變跨導乘法器的基本原理

    變跨導乘法器的基本原理 圖5.4-25為變跨導乘法器原理圖。它利用V1、V2管的跨導GM正比于恒流源電流IO,而IO又受另一個輸入電壓控制,而實
    發表于 05-18 14:48 ?3186次閱讀
    變跨導乘法器的<b class='flag-5'>基本原理</b>

    網絡監控的基本原理標準介紹

    網絡監控的基本原理標準介紹
    發表于 11-08 17:46 ?88次下載

    標準IO的操作原理及操作函數相關資料下載

    標準IO的操作原理及操作函數相關資料下載
    發表于 04-03 16:53 ?4次下載

    如何使用io.Reader和io.Writer接口在程序中實現流式IO

    Go 語言標準io 包內有一些常用接口和方法,本文配合圖片和實際代碼,詳細介紹了 io 包。 前言 在 Go 中,輸入和輸出操作是使用原語實現的,這些原語將數據模擬成可讀的或可寫的字節流。 為此
    的頭像 發表于 07-29 16:46 ?3252次閱讀

    嵌入式Linux開發系統開發之《一節課搞懂文件IO標準IO

    嵌入式Linux開發系統開發之《一節課搞懂文件IO標準IO》http://www.makeru.com.cn/live/5413_2293.html?s=47236
    發表于 11-01 17:37 ?10次下載
    嵌入式Linux開發<b class='flag-5'>系統</b>開發之《一節課搞懂文件<b class='flag-5'>IO</b>與<b class='flag-5'>標準</b><b class='flag-5'>IO</b>》

    怎樣將IO設備分配給IO控制器?

    PROFINET IO 系統由一個 PROFINET IO 控制器和其分配的 PROFINET IO 設備組成。當添加了 IO 控制器和
    的頭像 發表于 12-21 09:57 ?3461次閱讀

    使用STM32F10xxx SWJ引腳作為標準IO

    本文介紹了如何使用GPIO固件庫來釋放SWJ-DP引腳(串行JTAG調試端口),并且重用為標準IO。SWJ-DP IO能夠用作標準IOs,它的性能可以達到
    的頭像 發表于 12-23 11:47 ?2660次閱讀

    多路IO復用模型和異步IO模型介紹

    多路 IO 復用模型 多路 IO 復用,有時也稱為事件驅動 IO。它的基本原理就是有個函數會不斷地輪詢所負責的所有 socket ,當某個 socket有數據到達了,就通知用戶進程。
    的頭像 發表于 10-08 17:21 ?754次閱讀
    多路<b class='flag-5'>IO</b>復用模型和異步<b class='flag-5'>IO</b>模型介紹

    信號驅動IO與異步IO的區別

    一. 談信號驅動IO (對比異步IO來看) 信號驅動IO 對比 異步 IO進行理解 信號驅動IO: 內核將數據準備好的時候, 使用SIGIO
    的頭像 發表于 11-08 15:32 ?997次閱讀
    信號驅動<b class='flag-5'>IO</b>與異步<b class='flag-5'>IO</b>的區別