硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1419|回复: 12
收起左侧

[其它] 无锁FIFO用于前后台数据交互

  [复制链接]

38

主题

291

回帖

405

积分

高级会员

积分
405
发表于 2021-12-16 16:55:43 | 显示全部楼层 |阅读模式
近日在移植代码的过程中,发现MicroCHIP的ASF3库里带的FIFO数据结构代码比较有意思

是个简单有效的无锁FIFO实现。用于前后台程序之间数据搬运处理,通过约束读写操作,实现不需要的加临界区资源保护的处理。

源码分享给大伙,有兴趣可以看看。

fifo.c (3.21 KB, 下载次数: 70)

fifo.h (2.28 KB, 下载次数: 76)





回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106828
QQ
发表于 2021-12-16 17:23:29 | 显示全部楼层
这代码做的真简洁,值得看看
  1. /**
  2. * \file fifo.c
  3. *
  4. * \brief FIFO definitions
  5. *
  6. * Copyright (c) 2018 Microchip Technology Inc. and its subsidiaries.
  7. *
  8. * \asf_license_start
  9. *
  10. * \page License
  11. *
  12. * Subject to your compliance with these terms, you may use Microchip
  13. * software and any derivatives exclusively with Microchip products.
  14. * It is your responsibility to comply with third party license terms applicable
  15. * to your use of third party software (including open source software) that
  16. * may accompany Microchip software.
  17. *
  18. * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
  19. * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
  20. * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
  21. * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
  22. * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
  23. * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
  24. * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
  25. * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
  26. * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
  27. * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
  28. * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
  29. *
  30. * \asf_license_stop
  31. */
  32. /*
  33. * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
  34. */

  35. /*
  36.    lock-free FIFO, used to receive data in ISR context,
  37.    and process it in Main context
  38.    for optimization size MUST be power of 2, ie 2, 4, 8, 16, 32, ...
  39. */
  40. #include "fifo.h"
  41. #include <stddef.h>

  42. uint8_t fifo_init(fifo_t *const fifo, uint8_t *const buffer, const uint32_t size)
  43. {
  44.     /* check buffer pointer, and buffer size
  45.                 buffer size MUST be 2 to the power n
  46.         */
  47.     if (NULL != fifo && size > 0 && (size & (size - 1)) == 0)
  48.     {
  49.         fifo->buffer = buffer;
  50.         fifo->size = size;
  51.         /* valid indexes can be used to access array of size n is from 0 to n-1
  52.                         mask used to get the valid index to access fifo buffer from wr_idx and rd_idx
  53.                         for example size = 128 (dec) = 00000080 (hex) = 00000000000000000000000010000000 (bin)
  54.             mask = 127 (dec) = 0000007F (hex) = 00000000000000000000000001111111 (bin)
  55.                 */
  56.         fifo->mask = size - 1;
  57.         fifo->wr_idx = 0;
  58.         fifo->rd_idx = 0;
  59.         return 1;
  60.     }
  61.     return 0;
  62. }
  63. uint8_t fifo_empty(fifo_t *const fifo)
  64. {
  65.     return (fifo->wr_idx == fifo->rd_idx);
  66. }
  67. uint8_t fifo_full(fifo_t *const fifo)
  68. {
  69.     return ((fifo->wr_idx - fifo->rd_idx) == fifo->size);
  70. }
  71. uint8_t fifo_get(fifo_t *const fifo, uint8_t *const byte)
  72. {
  73.     if (!fifo_empty(fifo))
  74.     {
  75.         /* get the valid index from rd_idx by masking current rd_idx with pre calculated mask
  76.                         it will convert all bit to zeros except bits inside valid range of bits
  77.                 */
  78.         *byte = fifo->buffer[fifo->mask & fifo->rd_idx++];
  79.         return 1;
  80.     }
  81.     return 0;
  82. }
  83. uint8_t fifo_put(fifo_t *const fifo, const uint8_t byte)
  84. {
  85.     if (!fifo_full(fifo))
  86.     {
  87.         /* get the valid index from rd_idx by masking current wr_idx with pre calculated mask
  88.                         it will convert all bit to zeros except bits inside valid range of bits
  89.                 */
  90.         fifo->buffer[fifo->mask & fifo->wr_idx++] = byte;
  91.         return 1;
  92.     }
  93.     return 0;
  94. }
复制代码

  1. /**
  2. * \file fifo.h
  3. *
  4. * \brief FIFO declarations
  5. *
  6. * Copyright (c) 2018 Microchip Technology Inc. and its subsidiaries.
  7. *
  8. * \asf_license_start
  9. *
  10. * \page License
  11. *
  12. * Subject to your compliance with these terms, you may use Microchip
  13. * software and any derivatives exclusively with Microchip products.
  14. * It is your responsibility to comply with third party license terms applicable
  15. * to your use of third party software (including open source software) that
  16. * may accompany Microchip software.
  17. *
  18. * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
  19. * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
  20. * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
  21. * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
  22. * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
  23. * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
  24. * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
  25. * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
  26. * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
  27. * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
  28. * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
  29. *
  30. * \asf_license_stop
  31. */
  32. /*
  33. * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
  34. */

  35. /*
  36.    lock-free FIFO, used to receive data in ISR context,
  37.    and process it in Main context
  38.    for optimization size MUST be power of 2, ie 2, 4, 8, 16, 32, ...
  39. */
  40. #ifndef __FIFO_H__
  41. #define __FIFO_H__

  42. #include <stdint.h>
  43. #include <stdbool.h>
  44. typedef struct fifo_handle_tag
  45. {
  46.     volatile uint32_t wr_idx; /* counter for FIFO input, inc in ISR only */
  47.     volatile uint32_t rd_idx; /* counter for FIFO output, inc in MAIN only */
  48.     uint32_t size;            /* FIFO buffer size */
  49.     uint32_t mask;            /* Mask to extract buffer index from counters */
  50.     uint8_t *buffer;          /* FIFO buffer */
  51. } fifo_t;
  52. uint8_t fifo_init(fifo_t *const fifo, uint8_t *const buffer, const uint32_t size);
  53. uint8_t fifo_empty(fifo_t *const fifo);
  54. uint8_t fifo_full(fifo_t *const fifo);
  55. uint8_t fifo_get(fifo_t *const fifo, uint8_t *const byte);
  56. uint8_t fifo_put(fifo_t *const fifo, const uint8_t byte);

  57. #endif //__FIFO_H__
复制代码


回复

使用道具 举报

1

主题

109

回帖

112

积分

初级会员

固件開發工程師

积分
112
QQ
发表于 2021-12-16 19:00:25 | 显示全部楼层
赞一个!
我之前用的是Linux Kernel中抽取的FIFO,也是要求Buffer长度必须为2的幂次。
回复

使用道具 举报

5

主题

95

回帖

110

积分

初级会员

积分
110
发表于 2021-12-18 00:03:10 | 显示全部楼层
mark
回复

使用道具 举报

73

主题

1194

回帖

1413

积分

至尊会员

积分
1413
发表于 2021-12-18 10:58:28 来自手机 | 显示全部楼层
mark
回复

使用道具 举报

15

主题

73

回帖

118

积分

初级会员

积分
118
发表于 2021-12-18 11:06:56 | 显示全部楼层
很好,看着想把buffer改写成结构体,封装一层数据
回复

使用道具 举报

2

主题

39

回帖

45

积分

新手上路

积分
45
发表于 2021-12-19 12:44:30 | 显示全部楼层
感谢分享,这里的idx如果溢出了会不会出问题?
回复

使用道具 举报

56

主题

904

回帖

1072

积分

至尊会员

积分
1072
发表于 2021-12-19 13:38:55 | 显示全部楼层
可以用linux的fifo,我自己一直用。 这个应该就是魔改的linux的fifo。
回复

使用道具 举报

3

主题

31

回帖

40

积分

新手上路

积分
40
发表于 2021-12-20 10:53:43 | 显示全部楼层
这是最新版的,fifo.c里只有初始化,剩余的操作都放到fifo.h,使用内联函数实现,实现的思想和语法很有参考意义。
,
  1. /**
  2. * \file
  3. *
  4. * \brief This file controls the software FIFO management.
  5. *
  6. * These functions manages FIFOs thanks to simple a API. The FIFO can
  7. * be 100% full thanks to a double-index range implementation. For example,
  8. * a FIFO of 4 elements can be implemented: the FIFO can really hold up to 4
  9. * elements.
  10. * This is particularly well suited for any kind of application needing a lot of
  11. * small FIFO.
  12. *
  13. * Copyright (c) 2010-2018 Microchip Technology Inc. and its subsidiaries.
  14. *
  15. * \asf_license_start
  16. *
  17. * \page License
  18. *
  19. * Subject to your compliance with these terms, you may use Microchip
  20. * software and any derivatives exclusively with Microchip products.
  21. * It is your responsibility to comply with third party license terms applicable
  22. * to your use of third party software (including open source software) that
  23. * may accompany Microchip software.
  24. *
  25. * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
  26. * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
  27. * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
  28. * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
  29. * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
  30. * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
  31. * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
  32. * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
  33. * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
  34. * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
  35. * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
  36. *
  37. * \asf_license_stop
  38. *
  39. */
  40. /*
  41. * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
  42. */

  43. #ifndef _FIFO_H_
  44. #define _FIFO_H_

  45. #include "compiler.h"

  46. /**
  47. * \defgroup fifo_group First-In-First-Out Buffer (FIFO)
  48. *
  49. * See \ref fifo_quickstart.
  50. *
  51. * These functions manages FIFOs thanks to simple a API. The FIFO can
  52. * be 100% full thanks to a double-index range implementation. For example,
  53. * a FIFO of 4 elements can be implemented: the FIFO can really hold up to 4
  54. * elements. This is particularly well suited for any kind of application
  55. * needing a lot of small FIFO. The maximum fifo size is 128 items (uint8,
  56. * uint16 or uint32). Note that the driver, thanks to its conception, does
  57. * not use interrupt protection.
  58. *
  59. * @{
  60. */

  61. //! Error codes used by FIFO driver.
  62. enum {
  63.         FIFO_OK = 0,          //!< Normal operation.
  64.         FIFO_ERROR_OVERFLOW,  //!< Attempt to push something in a FIFO that is full.
  65.         FIFO_ERROR_UNDERFLOW, //!< Attempt to pull something from a FIFO that is empty
  66.         FIFO_ERROR,           //!< Error condition during FIFO initialization
  67. };

  68. //! FIFO descriptor used by FIFO driver.
  69. struct fifo_desc {
  70.         union
  71.         {
  72.                 uint32_t *u32ptr; //!< Pointer to unsigned-32 bits location
  73.                 uint16_t *u16ptr; //!< Pointer to unsigned-16 bits location
  74.                 uint8_t  *u8ptr;  //!< Pointer to unsigned-8 bits location
  75.         }  buffer;
  76.         volatile uint8_t read_index;  //!< Read index
  77.         volatile uint8_t write_index; //!< Write index
  78.         uint8_t size;                 //!< Size of the FIFO (unit is in number of 'element')
  79.         uint8_t mask;                 //!< Mask used to speed up FIFO operation (wrapping)
  80. };

  81. typedef struct fifo_desc fifo_desc_t;

  82. /**
  83. *  \brief Initializes a new software FIFO for a certain 'size'.
  84. *
  85. *  \pre Both fifo descriptor and buffer must be allocated by the caller before.
  86. *
  87. *  \param fifo_desc  Pointer on the FIFO descriptor.
  88. *  \param buffer     Pointer on the FIFO buffer.
  89. *  \param size       Size of the buffer (unit is in number of 'elements').
  90. *                    It must be a 2-power and <= to 128.
  91. *
  92. *  \return Status
  93. *    \retval FIFO_OK when no error occurred.
  94. *    \retval FIFO_ERROR when the size is not a 2-power.
  95. */
  96. int fifo_init(fifo_desc_t *fifo_desc, void *buffer, uint8_t size);

  97. /**
  98. *  \brief Returns the number of elements in the FIFO.
  99. *
  100. *  \param fifo_desc  The FIFO descriptor.
  101. *
  102. *  \return The number of used elements.
  103. */
  104. static inline uint8_t fifo_get_used_size(fifo_desc_t *fifo_desc)
  105. {
  106.         return ((fifo_desc->write_index - fifo_desc->read_index) & fifo_desc->mask);
  107. }

  108. /**
  109. *  \brief Returns the remaining free spaces of the FIFO (in number of elements).
  110. *
  111. *  \param fifo_desc  The FIFO descriptor.
  112. *
  113. *  \return The number of free elements.
  114. */
  115. static inline uint8_t fifo_get_free_size(fifo_desc_t *fifo_desc)
  116. {
  117.         return fifo_desc->size - fifo_get_used_size(fifo_desc);
  118. }

  119. /**
  120. *  \brief Tests if a FIFO is empty.
  121. *
  122. *  \param fifo_desc  The FIFO descriptor.
  123. *
  124. *  \return Status
  125. *    \retval true when the FIFO is empty.
  126. *    \retval false when the FIFO is not empty.
  127. */
  128. static inline bool fifo_is_empty(fifo_desc_t *fifo_desc)
  129. {
  130.         return (fifo_desc->write_index == fifo_desc->read_index);
  131. }

  132. /**
  133. *  \brief Tests if a FIFO is full.
  134. *
  135. *  \param fifo_desc  The FIFO descriptor.
  136. *
  137. *  \return Status
  138. *    \retval true when the FIFO is full.
  139. *    \retval false when the FIFO is not full.
  140. */
  141. static inline bool fifo_is_full(fifo_desc_t *fifo_desc)
  142. {
  143.         return (fifo_get_used_size(fifo_desc) == fifo_desc->size);
  144. }

  145. /**
  146. *  \brief Puts a new 8-bits element into the FIFO.
  147. *
  148. *  \param fifo_desc  The FIFO descriptor.
  149. *  \param item       extracted element.
  150. */
  151. static inline void fifo_push_uint8_nocheck(fifo_desc_t *fifo_desc, uint32_t item)
  152. {
  153.         uint8_t write_index;

  154.         write_index = fifo_desc->write_index;
  155.         fifo_desc->buffer.u8ptr[write_index & (fifo_desc->mask >> 1)] = item;
  156.         write_index = (write_index + 1) & fifo_desc->mask;

  157.         // Must be the last thing to do.
  158.         barrier();
  159.         fifo_desc->write_index = write_index;
  160. }

  161. /**
  162. *  \brief Puts a new 8-bits element into the FIFO and
  163. *         checks for a possible overflow.
  164. *
  165. *  \param fifo_desc  The FIFO descriptor.
  166. *  \param item       extracted element.
  167. *
  168. *  \return Status
  169. *    \retval FIFO_OK when no error occurred.
  170. *    \retval FIFO_ERROR_UNDERFLOW when the FIFO was empty.
  171. */
  172. static inline int fifo_push_uint8(fifo_desc_t *fifo_desc, uint32_t item)
  173. {
  174.         uint8_t write_index;

  175.         if (fifo_is_full(fifo_desc)) {
  176.                 return FIFO_ERROR_OVERFLOW;
  177.         }

  178.         write_index = fifo_desc->write_index;
  179.         fifo_desc->buffer.u8ptr[write_index & (fifo_desc->mask >> 1)] = item;
  180.         write_index = (write_index + 1) & fifo_desc->mask;

  181.         // Must be the last thing to do.
  182.         barrier();
  183.         fifo_desc->write_index = write_index;

  184.         return FIFO_OK;
  185. }

  186. /**
  187. *  \brief Puts a new 16-bits element into the FIFO.
  188. *
  189. *  \param fifo_desc  The FIFO descriptor.
  190. *  \param item       extracted element.
  191. */
  192. static inline void fifo_push_uint16_nocheck(fifo_desc_t *fifo_desc, uint32_t item)
  193. {
  194.         uint8_t write_index;

  195.         write_index = fifo_desc->write_index;
  196.         fifo_desc->buffer.u16ptr[write_index & (fifo_desc->mask >> 1)] = item;
  197.         write_index = (write_index + 1) & fifo_desc->mask;

  198.         // Must be the last thing to do.
  199.         barrier();
  200.         fifo_desc->write_index = write_index;
  201. }

  202. /**
  203. *  \brief Puts a new 16-bits element into the FIFO and
  204. *         checks for a possible overflow.
  205. *
  206. *  \param fifo_desc  The FIFO descriptor.
  207. *  \param item       extracted element.
  208. *
  209. *  \return Status
  210. *    \retval FIFO_OK when no error occurred.
  211. *    \retval FIFO_ERROR_UNDERFLOW when the FIFO was empty.
  212. */
  213. static inline int fifo_push_uint16(fifo_desc_t *fifo_desc, uint32_t item)
  214. {
  215.         uint8_t write_index;

  216.         if (fifo_is_full(fifo_desc)) {
  217.                 return FIFO_ERROR_OVERFLOW;
  218.         }

  219.         write_index = fifo_desc->write_index;
  220.         fifo_desc->buffer.u16ptr[write_index & (fifo_desc->mask >> 1)] = item;
  221.         write_index = (write_index + 1) & fifo_desc->mask;

  222.         // Must be the last thing to do.
  223.         barrier();
  224.         fifo_desc->write_index = write_index;

  225.         return FIFO_OK;
  226. }

  227. /**
  228. *  \brief Puts a new 32-bits element into the FIFO.
  229. *
  230. *  \param fifo_desc  The FIFO descriptor.
  231. *  \param item       extracted element.
  232. */
  233. static inline void fifo_push_uint32_nocheck(fifo_desc_t *fifo_desc, uint32_t item)
  234. {
  235.         uint8_t write_index;

  236.         write_index = fifo_desc->write_index;
  237.         fifo_desc->buffer.u32ptr[write_index & (fifo_desc->mask >> 1)] = item;
  238.         write_index = (write_index + 1) & fifo_desc->mask;

  239.         // Must be the last thing to do.
  240.         barrier();
  241.         fifo_desc->write_index = write_index;
  242. }

  243. /**
  244. *  \brief Puts a new 32-bits element into the FIFO and
  245. *         checks for a possible overflow.
  246. *
  247. *  \param fifo_desc  The FIFO descriptor.
  248. *  \param item       extracted element.
  249. *
  250. *  \return Status
  251. *    \retval FIFO_OK when no error occurred.
  252. *    \retval FIFO_ERROR_UNDERFLOW when the FIFO was empty.
  253. */
  254. static inline int fifo_push_uint32(fifo_desc_t *fifo_desc, uint32_t item)
  255. {
  256.         uint8_t write_index;

  257.         if (fifo_is_full(fifo_desc)) {
  258.                 return FIFO_ERROR_OVERFLOW;
  259.         }

  260.         write_index = fifo_desc->write_index;
  261.         fifo_desc->buffer.u32ptr[write_index & (fifo_desc->mask >> 1)] = item;
  262.         write_index = (write_index + 1) & fifo_desc->mask;

  263.         // Must be the last thing to do.
  264.         barrier();
  265.         fifo_desc->write_index = write_index;

  266.         return FIFO_OK;
  267. }

  268. /**
  269. *  \brief Gets a 8-bits element from the FIFO.
  270. *
  271. *  \param fifo_desc  The FIFO descriptor.
  272. *
  273. *  \return extracted element.
  274. */
  275. static inline uint8_t fifo_pull_uint8_nocheck(fifo_desc_t *fifo_desc)
  276. {
  277.         uint8_t read_index;
  278.         uint8_t item;

  279.         read_index = fifo_desc->read_index;
  280.         item = fifo_desc->buffer.u8ptr[read_index & (fifo_desc->mask >> 1)];
  281.         read_index = (read_index + 1) & fifo_desc->mask;

  282.         // Must be the last thing to do.
  283.         barrier();
  284.         fifo_desc->read_index = read_index;

  285.         return item;
  286. }

  287. /**
  288. *  \brief Gets a 8-bits element from the FIFO and
  289. *         checks for a possible underflow.
  290. *
  291. *  \param fifo_desc  The FIFO descriptor.
  292. *  \param item       extracted element.
  293. *
  294. *  \return Status
  295. *    \retval FIFO_OK when no error occurred.
  296. *    \retval FIFO_ERROR_UNDERFLOW when the FIFO was empty.
  297. */
  298. static inline int fifo_pull_uint8(fifo_desc_t *fifo_desc, uint8_t *item)
  299. {
  300.         uint8_t read_index;

  301.         if (fifo_is_empty(fifo_desc)) {
  302.                 return FIFO_ERROR_UNDERFLOW;
  303.         }

  304.         read_index = fifo_desc->read_index;
  305.         *item = fifo_desc->buffer.u8ptr[read_index & (fifo_desc->mask >> 1)];
  306.         read_index = (read_index + 1) & fifo_desc->mask;

  307.         // Must be the last thing to do.
  308.         barrier();
  309.         fifo_desc->read_index = read_index;

  310.         return FIFO_OK;
  311. }

  312. /**
  313. *  \brief Gets a 16-bits element from the FIFO.
  314. *
  315. *  \param fifo_desc  The FIFO descriptor.
  316. *
  317. *  \return extracted element.
  318. */
  319. static inline uint16_t fifo_pull_uint16_nocheck(fifo_desc_t *fifo_desc)
  320. {
  321.         uint8_t read_index;
  322.         uint16_t item;

  323.         read_index = fifo_desc->read_index;
  324.         item = fifo_desc->buffer.u16ptr[read_index & (fifo_desc->mask >> 1)];
  325.         read_index = (read_index + 1) & fifo_desc->mask;

  326.         // Must be the last thing to do.
  327.         barrier();
  328.         fifo_desc->read_index = read_index;

  329.         return item;
  330. }

  331. /**
  332. *  \brief Gets a 16-bits element from the FIFO and
  333. *         checks for a possible underflow.
  334. *
  335. *  \param fifo_desc  The FIFO descriptor.
  336. *  \param item       extracted element.
  337. *
  338. *  \return Status
  339. *    \retval FIFO_OK when no error occurred.
  340. *    \retval FIFO_ERROR_UNDERFLOW when the FIFO was empty.
  341. */
  342. static inline int fifo_pull_uint16(fifo_desc_t *fifo_desc, uint16_t *item)
  343. {
  344.         uint8_t read_index;

  345.         if (fifo_is_empty(fifo_desc)) {
  346.                 return FIFO_ERROR_UNDERFLOW;
  347.         }

  348.         read_index = fifo_desc->read_index;
  349.         *item = fifo_desc->buffer.u16ptr[read_index & (fifo_desc->mask >> 1)];
  350.         read_index = (read_index + 1) & fifo_desc->mask;

  351.         // Must be the last thing to do.
  352.         barrier();
  353.         fifo_desc->read_index = read_index;

  354.         return FIFO_OK;
  355. }

  356. /**
  357. *  \brief Gets a 32-bits element from the FIFO
  358. *
  359. *  \param fifo_desc  The FIFO descriptor.
  360. *
  361. *  \return extracted element.
  362. */
  363. static inline uint32_t fifo_pull_uint32_nocheck(fifo_desc_t *fifo_desc)
  364. {
  365.         uint8_t read_index;
  366.         uint32_t item;

  367.         read_index = fifo_desc->read_index;
  368.         item = fifo_desc->buffer.u32ptr[read_index & (fifo_desc->mask >> 1)];
  369.         read_index = (read_index + 1) & fifo_desc->mask;

  370.         // Must be the last thing to do.
  371.         barrier();
  372.         fifo_desc->read_index = read_index;

  373.         return item;
  374. }

  375. /**
  376. *  \brief Gets a 32-bits element from the FIFO and
  377. *         checks for a possible underflow.
  378. *
  379. *  \param fifo_desc  The FIFO descriptor.
  380. *  \param item       extracted element.
  381. *
  382. *  \return Status
  383. *    \retval FIFO_OK when no error occurred.
  384. *    \retval FIFO_ERROR_UNDERFLOW when the FIFO was empty.
  385. */
  386. static inline int fifo_pull_uint32(fifo_desc_t *fifo_desc, uint32_t *item)
  387. {
  388.         uint8_t read_index;

  389.         if (fifo_is_empty(fifo_desc)) {
  390.                 return FIFO_ERROR_UNDERFLOW;
  391.         }

  392.         read_index = fifo_desc->read_index;
  393.         *item = fifo_desc->buffer.u32ptr[read_index & (fifo_desc->mask >> 1)];
  394.         read_index = (read_index + 1) & fifo_desc->mask;

  395.         // Must be the last thing to do.
  396.         barrier();
  397.         fifo_desc->read_index = read_index;

  398.         return FIFO_OK;
  399. }

  400. /**
  401. *  \brief Gets a 32-bits element from the FIFO but does
  402. *         not remove it from the FIFO.
  403. *
  404. *  \param fifo_desc  The FIFO descriptor.
  405. *
  406. *  \retval item      extracted element.
  407. */
  408. static inline uint32_t fifo_peek_uint32(fifo_desc_t *fifo_desc)
  409. {
  410.         return fifo_desc->buffer.u32ptr[fifo_desc->read_index & (fifo_desc->mask >> 1)];
  411. }

  412. /**
  413. *  \brief Gets a 16-bits element from the FIFO but does
  414. *         not remove it from the FIFO.
  415. *
  416. *  \param fifo_desc  The FIFO descriptor.
  417. *
  418. *  \retval item      extracted element.
  419. */
  420. static inline uint16_t fifo_peek_uint16(fifo_desc_t *fifo_desc)
  421. {
  422.         return fifo_desc->buffer.u16ptr[fifo_desc->read_index & (fifo_desc->mask >> 1)];
  423. }

  424. /**
  425. *  \brief Gets a 8-bits element from the FIFO but does
  426. *         not remove it from the FIFO.
  427. *
  428. *  \param fifo_desc  The FIFO descriptor.
  429. *
  430. *  \retval item      extracted element.
  431. */
  432. static inline uint8_t fifo_peek_uint8(fifo_desc_t *fifo_desc)
  433. {
  434.         return fifo_desc->buffer.u8ptr[fifo_desc->read_index & (fifo_desc->mask >> 1)];
  435. }

  436. /**
  437. *  \brief Flushes a software FIFO.
  438. *
  439. *  \param fifo_desc  The FIFO descriptor.
  440. */
  441. static inline void fifo_flush(fifo_desc_t *fifo_desc)
  442. {
  443.         // Fifo starts empty.
  444.         fifo_desc->read_index = fifo_desc->write_index = 0;
  445. }

  446. /**
  447. * @}
  448. */

  449. /**
  450. * \page fifo_quickstart Quick start guide for First-In-First-Out Buffer (FIFO)
  451. *
  452. * This is the quick start guide for the \ref fifo_group, with
  453. * step-by-step instructions on how to configure and use the driver in a
  454. * selection of use cases.
  455. *
  456. * The use cases contain several code fragments. The code fragments in the
  457. * steps for setup can be copied into a custom initialization function, while
  458. * the steps for usage can be copied into, e.g., the main application function.
  459. *
  460. * \section fifo_use_cases FIFO use cases
  461. * - \ref fifo_basic_use_case
  462. * - \subpage fifo_use_case_1
  463. *
  464. * \section fifo_basic_use_case Basic use case - Push and pull
  465. * In this use case, an element will be pushed to the FIFO, and the same
  466. * element will be pulled from it.
  467. *
  468. * \section fifo_basic_use_case_setup Setup steps
  469. *
  470. * \subsection fifo_basic_use_case_setup_code Example code
  471. * The following must be added to the project:
  472. * \code
  473.         #define FIFO_BUFFER_LENGTH  4
  474.         #define PUSH_VALUE          0x12345678
  475.         union buffer_element {
  476.            uint8_t  byte;
  477.            uint16_t halfword;
  478.            uint32_t word;
  479.         };
  480. \endcode
  481. *
  482. * Add to application initialization:
  483. * \code
  484.         union buffer_element fifo_buffer[FIFO_BUFFER_LENGTH];
  485.         fifo_desc_t fifo_desc;
  486.         fifo_init(&fifo_desc, fifo_buffer, FIFO_BUFFER_LENGTH);
  487. \endcode
  488. *
  489. * \subsection fifo_basic_use_case_setup_flow Workflow
  490. * -# Create a FIFO buffer of FIFO_BUFFER_LENGTH elements, capable
  491. * of holding a byte, halfword or word:
  492. *   - \code union buffer_element fifo_buffer[FIFO_BUFFER_LENGTH]; \endcode
  493. * -# Create a FIFO buffer descriptor that contains information about the
  494. * location of the FIFO buffer, its size and where to read from or write to
  495. * upon the next buffer pull or push:
  496. *   - \code fifo_desc_t fifo_desc; \endcode
  497. * -# Initialize the FIFO:
  498. *   - \code fifo_init(&fifo_desc, fifo_buffer, FIFO_BUFFER_LENGTH); \endcode
  499. *
  500. * \section fifo_basic_use_case_usage Usage steps
  501. *
  502. * \subsection fifo_basic_use_case_usage_code Example code
  503. * Add to application C-file:
  504. * \code
  505.         uint8_t status;
  506.         uint8_t pull_value;
  507.         status = fifo_push_uint8(&fifo_desc, PUSH_VALUE & 0xff);
  508.         status = fifo_pull_uint8(&fifo_desc, &pull_value);
  509. \endcode
  510. *
  511. * \subsection fifo_basic_use_case_usage_flow Workflow
  512. * -# Create a variable to hold the return status from the FIFO:
  513. *   - \code uint8_t status; \endcode
  514. * -# Create a variable to hold the pulled value from the FIFO:
  515. *   - \code uint8_t pull_value; \endcode
  516. * -# Put a new 8-bit element into the FIFO:
  517. *   - \code status = fifo_push_uint8(&fifo_desc, PUSH_VALUE & 0xff); \endcode
  518. * \note The status variable will contain \ref FIFO_OK if no error occurred.
  519. * -# Get the 8-bit element from the FIFO:
  520. *   - \code status = fifo_pull_uint8(&fifo_desc, &pull_value); \endcode
  521. * \note The status variable will contain \ref FIFO_OK if no error occurred.
  522. */

  523. /**
  524. * \page fifo_use_case_1 Push and flush
  525. *
  526. * In this use case, two elements will be pushed to the FIFO, and the FIFO
  527. * will be flushed.
  528. *
  529. * \section fifo_use_case_1_setup Setup steps
  530. *
  531. * \subsection fifo_use_case_1_setup_code Example code
  532. * The following must be added to the project:
  533. * \code
  534.         #define FIFO_BUFFER_LENGTH  4
  535.         #define PUSH_VALUE          0x12345678
  536.         union buffer_element {
  537.            uint8_t  byte;
  538.            uint16_t halfword;
  539.            uint32_t word;
  540.         };
  541. \endcode
  542. *
  543. * Add to application initialization:
  544. * \code
  545.         union buffer_element fifo_buffer[FIFO_BUFFER_LENGTH];
  546.         fifo_desc_t fifo_desc;
  547.         fifo_init(&fifo_desc, fifo_buffer, FIFO_BUFFER_LENGTH);
  548. \endcode
  549. *
  550. * \subsection fifo_use_case_1_setup_flow Workflow
  551. * -# Create a FIFO buffer of FIFO_BUFFER_LENGTH elements, capable
  552. * of holding a byte, halfword or word:
  553. *   - \code union buffer_element fifo_buffer[FIFO_BUFFER_LENGTH]; \endcode
  554. * -# Create a FIFO buffer descriptor that containing information about the
  555. * location of the FIFO buffer, its size and where to read from or write to
  556. * upon the next buffer pull or push:
  557. *   - \code fifo_desc_t fifo_desc; \endcode
  558. * -# Initialize the FIFO:
  559. *   - \code fifo_init(&fifo_desc, fifo_buffer, FIFO_BUFFER_LENGTH); \endcode
  560. * \section fifo_use_case_1_usage Usage steps
  561. *
  562. * \subsection fifo_use_case_1_usage_code Example code
  563. * Add to application C-file:
  564. * \code
  565.         uint8_t status;
  566.         bool fifo_empty;
  567.         status = fifo_push_uint16(&fifo_desc, PUSH_VALUE & 0xffff);
  568.         status = fifo_push_uint16(&fifo_desc, PUSH_VALUE & 0xffff);
  569.         fifo_flush(&fifo_desc);
  570.         fifo_empty = fifo_is_empty(&fifo_desc);
  571. \endcode
  572. *
  573. * \subsection fifo_use_case_1_usage_flow Workflow
  574. * -# Create a variable to hold the return status from the FIFO:
  575. *   - \code uint8_t status; \endcode
  576. * -# Create a variable to hold the pulled value from the FIFO:
  577. *   - \code uint16_t pull_value; \endcode
  578. * -# Put two new 16-bit element into the FIFO:
  579. *   - \code status = fifo_push_uint16(&fifo_desc, PUSH_VALUE & 0xffff); \endcode
  580. *   - \code status = fifo_push_uint16(&fifo_desc, PUSH_VALUE & 0xffff); \endcode
  581. * \note The status variable will contain \ref FIFO_OK if no error occurred.
  582. * -# Flush the FIFO:
  583. *   - \code fifo_flush(&fifo_desc); \endcode
  584. * -# Check that the FIFO is empty after flushing:
  585. *   - \code fifo_empty = fifo_is_empty(&fifo_desc); \endcode
  586. * \note The fifo_empty variable will be true if the FIFO is empty.
  587. */

  588. #endif  // _FIFO_H_
复制代码
回复

使用道具 举报

3

主题

31

回帖

40

积分

新手上路

积分
40
发表于 2021-12-20 10:54:20 | 显示全部楼层
fifo.c:
  1. /**
  2. * \file
  3. *
  4. * \brief This file controls the software FIFO management.
  5. *
  6. * These functions manages FIFOs thanks to simple a API. The FIFO can
  7. * be 100% full thanks to a double-index range implementation. For example,
  8. * a FIFO of 4 elements can be implemented: the FIFO can really hold up to 4
  9. * elements.
  10. * This is particularly well suited for any kind of application needing a lot of
  11. * small FIFO.
  12. *
  13. * Copyright (c) 2010-2018 Microchip Technology Inc. and its subsidiaries.
  14. *
  15. * \asf_license_start
  16. *
  17. * \page License
  18. *
  19. * Subject to your compliance with these terms, you may use Microchip
  20. * software and any derivatives exclusively with Microchip products.
  21. * It is your responsibility to comply with third party license terms applicable
  22. * to your use of third party software (including open source software) that
  23. * may accompany Microchip software.
  24. *
  25. * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
  26. * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
  27. * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
  28. * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
  29. * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
  30. * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
  31. * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
  32. * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
  33. * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
  34. * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
  35. * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
  36. *
  37. * \asf_license_stop
  38. *
  39. */
  40. /*
  41. * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
  42. */

  43. #include "fifo.h"

  44. int fifo_init(fifo_desc_t *fifo_desc, void *buffer, uint8_t size)
  45. {
  46.         // Check the size parameter. It must be not null...
  47.         Assert (size);

  48.         // ... must be a 2-power ...
  49.         Assert (!(size & (size - 1)));

  50.         // ... and must fit in a uint8_t. Since the read and write indexes are using a
  51.         // double-index range implementation, the max FIFO size is thus 128 items.
  52.         Assert (size <= 128);

  53.         // Fifo starts empty.
  54.         fifo_desc->read_index  = 0;
  55.         fifo_desc->write_index = 0;

  56.         // Save the size parameter.
  57.         fifo_desc->size = size;

  58.         // Create a mask to speed up the FIFO management (index swapping).
  59.         fifo_desc->mask = (2 * (uint16_t)size) - 1;

  60.         // Save the buffer pointer.
  61.         fifo_desc->buffer.u8ptr = buffer;

  62.         return FIFO_OK;
  63. }
复制代码
回复

使用道具 举报

3

主题

1223

回帖

1232

积分

至尊会员

积分
1232
发表于 2021-12-20 13:14:33 | 显示全部楼层

这个fifo模块,可以用在RTOS的多线程吗? 有什么禁忌事项吗?谢谢!
回复

使用道具 举报

3

主题

31

回帖

40

积分

新手上路

积分
40
发表于 2021-12-20 13:27:43 | 显示全部楼层
morning_enr6U 发表于 2021-12-20 13:14
这个fifo模块,可以用在RTOS的多线程吗? 有什么禁忌事项吗?谢谢!

我觉得可以用,而且不需要开关中断,item的数量是限制在uint8_t的范围之内的。
回复

使用道具 举报

38

主题

291

回帖

405

积分

高级会员

积分
405
 楼主| 发表于 2021-12-20 13:45:26 | 显示全部楼层
我的理解是这样的:

ISR函数和非ISR函数对读写索引的操作可认为是自动有临界区保护了

在线程函数中使用,这个前提不一定存在,所以慎用,或者还是得加锁

从Linux内核中抽出来的kfifo代码,本意也是在内核和用户态之间共享数据,也是有这个自动有锁效果的假设
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-6 13:52 , Processed in 0.354100 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表