aaarrr 69 4 июня, 2021 Опубликовано 4 июня, 2021 · Жалоба Ну а bufio_* где искать? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 5 июня, 2021 Опубликовано 5 июня, 2021 · Жалоба 22 hours ago, aaarrr said: Ну а bufio_* где искать? Spoiler /*------------------------------------------------------------------------------ * Name: HAL_BufIO.h * Purpose: buffered IO - support of interrupt driven IO over a serial device * * Version: V1.05 *------------------------------------------------------------------------------ * History: * 28.03.20 V1.05: Extern definitions of symbols for USART driver macro * 22.08.14 V1.04: Adds bufio_PUSH() * 22.07.12 V1.03: Adds useful macros to init the _RING and _BUFFER items. * 20.10.11 V1.02: * - Ring buffer can manage elements of length > char. * - The interface to READ/WRITE has been changes, so * edit the modules using the functions. * - _RingGET() added. * V1.01 Char ring buffer support included * V1.00 Initial Version *----------------------------------------------------------------------------- * ROE: Rules of engagement. * * The "bufio" library offers a FIFO-based interrupt driven I/O and a ring * buffer object (see below). * * The FIFO-based interrupt driven I/O is mostly intended for an easy * implementation of a char terminal via UART but not only. * * It is hardware independent but expects the common I/O hardware behavior * like "ready to send" and "data received" flags, etc. Moreover, the state * machine of the library assumes, a "ready" flag being set, the (re)enabling * of the correspondent interrupt triggers the exception. Fortunately, Cortex * and 8051 peripherals like UART or SPI have the expected behavior in this * aspect. Refer to manuals of other MCU architectures before implementing * the hardware dependent functions. * * 1). * The user code must implement seven hardware dependent handler functions. * If either transmission or reception is not needed, the correspondent user * functions (related three of them) can be skipped (see also 2). below). * * The function names below are just for example: * * int16_t Get(void) - reads a value from the peripheral data register * void Send(int16_t value) - sends a value via peripheral * * uint8_t RX_Ready(void) - returns >0 if a value is available * uint8_t TX_Ready(void) - returns >0 if a peripheral is ready to send * uint8_t TC_Ready(void) - returns >0 if sending is complete * * void RXIE(uint8_t enable) - controls the "RX ready" interrupt flag, * void TXIE(uint8_t enable) - controls the "TX ready" interrupt flag * depending on the "enable" value: * enable > 0 - an interrupt to enable, * enable ==0 - an interrupt to disable. * * Examples of the implementation (ATMEL SAM3U Cortex M3, UART): * * void RXIE(uint8_t enable) * { * if (enable) UART->UART_IER = UART_IER_RXRDY; // enable RX interrupt * else UART->UART_IDR = UART_IER_RXRDY; // disable RX interrupt * } * * uint8_t RX_Ready(void) * { * return !!(UART->UART_SR & UART_SR_RXRDY); // return flag RXRDY * } * * etc... * * If reading or writing of a data register does not clear the corresponding * "ready" flags (like UART in 8051), they must be explicitly cleared * according to the peripheral features while handling the data register. * For 8051's UART it can look like: * * void Send(int16_t value) * { * TI = 0; // prior clear transmitter interrupt/ready flag * SBUF = Value; // send the value. * } * * Avoid clearing the flags in "RX_Ready" or "TX_Ready" functions because * the flags can be expected pending for some state machine cases. * * 2). * A structure of type "bufio_DRIVER" must be declared, and the * implemented handler functions listed above must be assigned to its fields * (watch the order!). * * const bufio_DRIVER U_Drv = { RXIE, // controls RX interrupt flag * TXIE, // controls TX interrupt flag * RX_Ready, // returns RX ready flag * TX_Ready, // returns TX ready flag * TC_Ready, // returns TC ready flag * Read_RX, // returns a value * Write_TX // sends a value * }; * * If either transmission or reception only is required, another fields * must contain NULL. * * 3). * A FIFO variable of "bufio_FIFO" type must be declared. * * The FIFO can keep byte- or word-wide items. It depends on the declaration * of the attached buffer. The field "size" of the "bufio_BUFFER" structure * must be set to either 0/1 for the byte-wide or to 2 for the word-wide data. * The FIFO item data width can be set for transmitter and receiver buffers * independently. * * Example of the byte FIFO implementation: * * char TXBuffer1[BufferDepth]; // TX buffer, byte-wide items * bufio_FIFO FIFO1 = { * {0,0,0, 1,0,NULL}, // no RX, * {0,0,BufferDepth, 1,0,TXBuffer1}, // TX only, byte-wide items * &U_Drv // Serial driver * }; * * Refer to "bufio_BUFFER" structure to see the field order. * * Above, only TX will be supported, the "bufio_BUFFER" structure for TX * field within the FIFO1 variable is initialized with the appropriate * values like BufferSize and TXBuffer1 pointer; the last field contains * the pointer to the bufio driver structure. Surely, the implementations * of the reception related user functions can be omitted here. * * 4). * The hardware dependent interrupt handler should redirect to the bufio * handler as follows (example for ATMEL SAM3U Cortex M3, UART): * * void UART_IRQHandler(void) * { * bufio_IRQHandler(&FIFO1); * } * * 5). * The published functions like "bufio_ReadChar" and "bufio_WriteChar" can * then be used to receive and send the data. * * Due to no static data, all the functions are reenterable and can process * several I/O devices via their own FIFO structures, of course. * * * RING: * * The Ring is a set of functions that provides a purely software driven FIFO * to manage elements that are merely buffers of an equal size(!) described * by the bufio_RING structure. The functions are reentrant. * * To create a ring, allocate and initialize the bufio_RING structure those * fields are commented below. * * Example of a char FIFO ring: * ---------------------------- * * // allocation * char buf[DEPTH]; * bufio_RING a_ring = {0, 0, DEPTH, sizeof(char), buf}; * * // alternatively, using the macro: * bufio_RING a_ring = BUFIO_RING_INIT(DEPTH, sizeof(char), buf); * * // usage * ... * char c = value; * ... * bufio_RingPUT(&a_ring, &c); * ... * if (bufio_RingGET(&a_ring, &c)) * { * // do job * } * * Example of a common data storage ring: * ------------------------------------------- * * // allocation * unsigned char buf[DEPTH]; * bufio_RING a_ring = {0, 0, DEPTH, SIZE, *buf}; * * // alternatively, using the macro: * bufio_RING a_ring = BUFIO_RING_INIT(DEPTH, SIZE, *buf); * * // usage * ... * unsigned char s; * ... * ... data in s are available... * ... * bufio_RingPUT(&a_ring, s); * ... * unsigned char s; * if (bufio_RingGET(&a_ring, s)) * { * // process s * } * *----------------------------------------------------------------------------*/ // #include <stdint.h> #include <string.h> #ifdef __cplusplus extern "C" { #endif #ifndef _HAL_BUFIO_H #define _HAL_BUFIO_H #ifndef CHAR_CR #define CHAR_CR '\r' #endif #ifndef CHAR_LF #define CHAR_LF '\n' #endif #ifndef __STATIC_INLINE #define __STATIC_INLINE static __inline #endif // ----------------------------------------------------------------------------- extern int sendchar (int ch); // for redirect.c extern int getkey (void); // for redirect.c extern int bufio_BreakCounter; // ----------------------------------------------------------------------------- // // Type definition set for the user functions // typedef void (*vpLogicSet)(uint8_t enable); typedef uint8_t (*vpLogicGet)(void); typedef void (*vpValueSet)(uint16_t value); typedef int32_t (*vpValueGet)(void); // ----------------------------------------------------------------------------- // // >>> RING <<< // typedef struct _bufio_ring { void *data; // data array pointer int16_t idx; // work write index int16_t cnt; // number of elements int16_t depth; // the ring buffer depth int16_t size; // the data item size } bufio_RING; #define BUFIO_RING_INIT(d,s,b) {b, 0, 0, d, s} #define BUFIO_RING_OF(a) \ BUFIO_RING_INIT(sizeof(a)/sizeof(a[0]), sizeof(a[0]), a) // ----------------------------------------------------------------------------- // // >>> FIFO <<< // typedef struct _bufio_buffer { void *data; // pointer to the data buffer int16_t idx; // index of the item in the buffer int16_t cnt; // number of items in the buffer int16_t depth; // capacity of the buffer int16_t size; // data size of the buffer items uint8_t flag; // internal critical section flag } bufio_BUFFER; // like bufio_RING but having a mutex flag #define BUFIO_BUFFER_INIT(d,s,b) {b, 0, 0, d, s, 0} #define BUFIO_BUFFER(buf) BUFIO_BUFFER_INIT(sizeof(buf),sizeof(buf[0]),buf) typedef const struct bufio_driver { vpLogicSet RIE; // RX interrupt enable/disable vpLogicSet TIE; // TX interrupt enable/disable vpLogicGet RI; // RX flag acquire vpLogicGet TI; // TX flag acquire vpLogicGet TC; // TC flag acquire vpValueGet Get; // get a value vpValueSet Send; // send a value } bufio_DRIVER; typedef struct bufio_fifo { bufio_BUFFER RX; // input FIFO buffer bufio_BUFFER TX; // output FIFO buffer bufio_DRIVER* HD; // pointer to driver } bufio_FIFO; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // >>> RING support <<< // __STATIC_INLINE void bufio_RingRESET(bufio_RING *ring) { if (ring) ring->idx = ring->cnt = 0; } // ----------------------------------------------------------------------------- __STATIC_INLINE void bufio_RingCLEAR(bufio_RING *ring) { if (ring && ring->data) memset(ring->data, 0, ring->size * ring->depth); } // ----------------------------------------------------------------------------- // // Returns the number of occupied elements in the ring. // __STATIC_INLINE unsigned int bufio_RingCOUNT(bufio_RING *ring) { return (ring ? ring->cnt : 0); } // ----------------------------------------------------------------------------- // // Returns TRUE (!=0) if the ring has no more room. // __STATIC_INLINE unsigned char bufio_RingFULL(bufio_RING *ring) { return (ring ? (ring->cnt >= ring->depth) : 0); } // ----------------------------------------------------------------------------- // // Returns a pointer to the stored element of the ring indexed by num. // or NULL if the ring is empty or num is out of range. // void *bufio_RingPEEK(bufio_RING *ring, int num); // ----------------------------------------------------------------------------- // // Returns a pointer to the stored top (first, oldest) element of the ring // (without changing the ring) or NULL if the ring is empty. // // The call to RingTOP() allows to get access to and process the element data // buffer without copying the data to any external buffer; the following // call to bufio_RingGET(ring, NULL) removes then the element from the ring. // // Dealing with the first element, nothing else but FIFO is implemented! // void *bufio_RingTOP(bufio_RING *ring); #define bufio_RingFIRST(r) bufio_RingTOP(r) // ----------------------------------------------------------------------------- // // Returns a pointer to the stored bottom (lately added) element of the ring // (without changing the ring) or NULL if the ring is empty. // // The call to RingBOTTOM() allows to get access to and process the element // data buffer without copying the data to any external buffer; the following // call to bufio_RingPOP(ring, NULL) removes then the element from the ring. // // Dealing with the last element, nothing else but STACK is implemented! // void *bufio_RingBOTTOM(bufio_RING *ring); #define bufio_RingLAST(r) bufio_RingBOTTOM(r) // ----------------------------------------------------------------------------- // // Gets the top (first, oldest) element from the ring into the buffer *c. // If c == NULL, just removes the top element from the ring. // Returns FALSE (==0) if no elements in the ring (ring is empty). // // Dealing with the first element, nothing else but FIFO is implemented! // unsigned char bufio_RingGET(bufio_RING *ring, void *c); // ----------------------------------------------------------------------------- // // Gets the bottom (lately added) element from the ring into the buffer *c. // If c == NULL, just removes the bottom element from the ring. // Returns FALSE (==0) if no elements in the ring (ring empty). // // Dealing with the last element, nothing else but STACK is implemented! // unsigned char bufio_RingPOP(bufio_RING *ring, void *c); // ----------------------------------------------------------------------------- // // Appends (copies) an element to the ring from the provided buffer *c. // Returns a pointer onto it or NULL (==0) if no more room has been available. // // If c == NULL, no data are copied but the element is appended to the ring. // The returned pointer onto the buffer can then be used to access // the buffer. This approach can be helpful to reuse the already allocated // (and not additional external) data space as a storage. // void *bufio_RingPUT(bufio_RING *ring, const void *c); // ----------------------------------------------------------------------------- // // Places (copies) an element in the ring from the provided buffer *c. // Returns a pointer onto it or NULL (==0) if no more room has been available. // // It places the data on the TOP. // // If c == NULL, no data are copied but the element is added to the ring. // The returned pointer onto the buffer can then be used to access // the buffer. This approach can be helpful to reuse the already allocated // (and not additional external) data space as a storage. // void *bufio_RingPUSH(bufio_RING *ring, const void *c); // ----------------------------------------------------------------------------- // // Compares an element given by num with the provided buffer *c. // Returns >0 if equal else 0 (also no data/wrong num). // unsigned char bufio_RingCOMP(bufio_RING *ring, const void *c, int num); // ----------------------------------------------------------------------------- // // Searches in the ring for an element provided by buffer *c. // Returns the number of the found element [0..count-1] or < 0 if none. // int bufio_RingFIND(bufio_RING *ring, const void *c); // ----------------------------------------------------------------------------- // // Deletes in the ring an element given by num // Returns >0 if the element has been deleted. // unsigned char bufio_RingDEL(bufio_RING *ring, int num); // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // >>> FIFO support <<< // // Returns the amount of bytes actually stored in the input (PC -> Device) FIFO // int16_t bufio_RXBufferLevel (bufio_FIFO *FIFO); // ----------------------------------------------------------------------------- // // Returns a number of bytes still available in the output (Device -> PC) FIFO // int16_t bufio_TXBufferCapacity(bufio_FIFO *FIFO); // ----------------------------------------------------------------------------- // // Returns true if the transmission is completed // unsigned char bufio_TXComplete(bufio_FIFO *FIFO); // ----------------------------------------------------------------------------- // // Flushes the input (PC -> Device) FIFO // void bufio_PurgeRX(bufio_FIFO *FIFO); // ----------------------------------------------------------------------------- // // Cancels the output (Device -> PC) FIFO // void bufio_PurgeTX(bufio_FIFO *FIFO); // ----------------------------------------------------------------------------- // // Processes a received value before placing it into the FIFO buffer. // Due to the weak declaration can be reimplemented by the user. // uint16_t bufio_InputFilter(uint16_t c); // ----------------------------------------------------------------------------- // // Stores a value in the software driven input (PC -> Device) FIFO buffer. // Returns -1 if no more place in the FIFO. // // CALLED FROM THE INTERRUPT HANDLER or an external routine that wanna inject // a value // int32_t bufio_StoreChar(bufio_FIFO *FIFO, uint16_t c); // ----------------------------------------------------------------------------- // // Places a value to the software driven output (Device -> PC) FIFO buffer // and starts the transmission by (re)enabling the Device interrupt. // Returns -1 if no place in the buffer more. // int32_t bufio_WriteChar(bufio_FIFO *FIFO, uint16_t c); // ----------------------------------------------------------------------------- // // Reads out a value from the input (PC -> Device) FIFO buffer. // returns -1 if empty. // // Intended for an external routine that processes the input stream. // int32_t bufio_ReadChar(bufio_FIFO *FIFO); // ----------------------------------------------------------------------------- // // Returns the first value from the input (PC -> Device) FIFO buffer without // destroying the FIFO or returns -1 if empty. // int32_t bufio_PeepChar(bufio_FIFO * FIFO); // ----------------------------------------------------------------------------- // // To be called from the Device IRQ handler // void bufio_IRQHandler(bufio_FIFO *FIFO); // ----------------------------------------------------------------------------- // // Prepares the bufio // void bufio_Init(bufio_FIFO *FIFO); /* ----------------------------------------------------------------------------- * * The help macro to define the USART driver buffers and the FIFO structure */ #define DEFINE_USART_BUFFERS(FIFONAME, RXSIZE, TXSIZE) \ static const bufio_DRIVER \ U_Drv = {RXIE, \ TXIE, \ RX_Ready, \ TX_Ready, \ TX_Complete, \ Read_RX, \ Write_TX \ }; \ \ static unsigned char rxBuffer[RXSIZE], \ txBuffer[TXSIZE]; \ static bufio_FIFO \ FIFONAME = {BUFIO_BUFFER(rxBuffer), \ BUFIO_BUFFER(txBuffer), \ &U_Drv} /* ----------------------------------------------------------------------------- * * The help macro below allows to define an USART driver. * The macro needs further macros like USART_RXIE_SET, etc., * that process the USART registers. Mostly, those macros are * defined specifically for each platform (CPU) in a "xxxx_proc.h" * file situated in HAL. * * USARTN is a CMSIS pointer to the peripheral (like USART1) * FIFONAME is a name of the driver FIFO. Mostly just 'FIFO'. * RXSIZE and TXSIZE are the depths of the FIFOs for TX and RX. */ #ifndef USART_FLAG_XE #define USART_FLAG_XE USART_FLAG_FE #endif #ifndef USART_STATE_CLEAR #define USART_STATE_CLEAR #endif #define DEFINE_USART_DRIVER(USARTN, FIFONAME, RXSIZE, TXSIZE) \ __attribute__((weak)) void FIFONAME##_Break(void) {} \ \ static void RXIE(uint8_t enable) \ { \ if (enable) USART_RXIE_SET (USARTN); \ else USART_RXIE_CLEAR(USARTN); \ } \ static void TXIE(uint8_t enable) \ { \ if (enable) USART_TXIE_SET (USARTN); \ else USART_TXIE_CLEAR(USARTN); \ } \ static uint8_t RX_Ready(void) \ { \ return USART_RI_SR(USARTN); \ } \ static uint8_t TX_Ready(void) \ { \ return USART_TI_SR(USARTN); \ } \ static uint8_t TX_Complete(void) \ { \ return USART_TC_SR(USARTN); \ } \ static void Write_TX(uint16_t value) \ { \ USART_PUT_DR(USARTN, value); \ } \ static int32_t Read_RX(void); \ DEFINE_USART_BUFFERS(FIFONAME, RXSIZE, TXSIZE); \ \ static int32_t Read_RX(void) \ { \ uint16_t st = USART_GET_SR(USARTN) & USART_RX_FLAGS; \ int32_t dr = USART_GET_DR(USARTN); \ if (st) \ { \ USART_STATE_CLEAR; \ if ((st & (USART_FLAG_XE)) && dr == 0) \ { \ bufio_PurgeRX(&FIFONAME); \ FIFONAME##_Break(); \ } \ } \ return dr; \ } // Unbelievable but just reading SR before in IRQ // helps not to lose bytes. Found on 28.04.2014. #define DEFINE_USART_DRIVER_IRQ(USARTN, FIFONAME, RXSIZE, TXSIZE, VECTOR) \ DEFINE_USART_DRIVER(USARTN, FIFONAME, RXSIZE, TXSIZE); \ void VECTOR(void) \ { \ USART_GET_SR(USARTN); \ bufio_IRQHandler(&FIFONAME); \ } #ifdef __cplusplus } #endif #endif // --- EOF --------------------------------------------------------------------- Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 5 июня, 2021 Опубликовано 5 июня, 2021 · Жалоба Ох нихрена-се наворочено. Мне FIFO как-то по проще видится, уж во всяком случае без индекса. #define fifo_size 256 union fifo { struct in { const volatile uint16_t tail; volatile uint16_t head; volatile char ptr[fifo_size]; }; struct out { volatile uint16_t tail; const volatile uint16_t head; volatile char ptr[fifo_size]; }; }; Всё очень просто: голова не может догнать хвост, хвост всегда догоняет голову. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 6 июня, 2021 Опубликовано 6 июня, 2021 · Жалоба 22 hours ago, AVI-crak said: Ох нихрена-се наворочено. Мне FIFO как-то по проще видится, уж во всяком случае без индекса. #define fifo_size 256 union fifo { struct in { const volatile uint16_t tail; volatile uint16_t head; volatile char ptr[fifo_size]; }; struct out { volatile uint16_t tail; const volatile uint16_t head; volatile char ptr[fifo_size]; }; }; Всё очень просто: голова не может догнать хвост, хвост всегда догоняет голову. 1. Существует две основные концепции построения кольцевых буферов: указатель и счетчик или два указателя. В первом случае счетчик сразу дает количество элементов в FIFO (мне было так удобней), но второй указатель надо вычислять; во втором случае указатели готовы всегда, но количество элементов надо каждый раз вычислять, если опрашивать. Эти концепции совершенно равноправны. Спорить по этому поводу равносильно тому, разбивать ли яйца с тупой или острой стороны. 2. У меня не просто FIFO, но с атомарным доступом, который достигается флагами и основан на свойстве прерываний в 8051 и CMx, когда их можно, скажем так, отложить. При этом не нужно запрещать/разрешать прерывания глобально ( __enable_irq(), __disable_irq()). Эта реализация может показаться несколько навороченной, но она хорошо работает без влияния на другие подсистемы или на всю подсистему прерываний. 3. Код реентерабельный, т.к. работает с внешними структурами данных. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 6 июня, 2021 Опубликовано 6 июня, 2021 · Жалоба 7 hours ago, KnightIgor said: Существует две основные концепции построения кольцевых буферов Вот специально для полной атомарности придумали FIFO с двумя указателями, без блокирования прерываний танцев с бубном. Два потока могут общаться через fifo, даже если выполняются на разных ядрах, одновременно. А посчитать свободное место или остаток - можно в любое время с любой стороны, и при этом не будет ошибок!!! Причём на FIFO можно натравить дма, оно конечно не полностью автоматически получится - но телодвижений будет на пару порядков меньше. Насчёт третьего пункта - не понимаю как и в чём оно должно вам помогать. FIFO - это не синхронный механизм связи, и уж точно не является объектом распространения зоны видимости, он всегда сам по себе - между двумя фиксированными потоками. Когда желающих больше - нужно либо больше разных FIFO, либо канальный уровень сверху, ну или арбитраж ресурсов. Но самого механизма FIFO - это вообще никак не касается, его дело простое - рулить буфером. Кстати я уже давно заметил, чем алгоритм проще - тем надёжнее работает. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 6 июня, 2021 Опубликовано 6 июня, 2021 · Жалоба 8 часов назад, KnightIgor сказал: 1. Существует две основные концепции построения кольцевых буферов: указатель и счетчик или два указателя. В первом случае счетчик сразу дает количество элементов в FIFO (мне было так удобней), но второй указатель надо вычислять; во втором случае указатели готовы всегда, но количество элементов надо каждый раз вычислять, если опрашивать. Эти концепции совершенно равноправны. Это неправда. Вариант с двумя указателями позволяет строить кольцевые буфера с одним писателем и одним читателем без дополнительных средств синхронизации потоков (типа запрета прерываний). Вариант со счётчиком - не позволяет. Если вы этого не знали, то тут как раз и может крыться причина багов. 8 часов назад, KnightIgor сказал: 2. У меня не просто FIFO, но с атомарным доступом, который достигается флагами и основан на свойстве прерываний в 8051 и CMx, когда их можно, скажем так, отложить. При этом не нужно запрещать/разрешать прерывания глобально ( __enable_irq(), __disable_irq()) Ничего не понятно, белиберда какая-то.... PS: Имхо конечно, но стиль оформления просто ужасный - исходный код не читаемый практически, какое-то нагромождение на ровном месте где не нужно... уж не говоря об оптимальности... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 9 июня, 2021 Опубликовано 9 июня, 2021 · Жалоба On 6/6/2021 at 10:05 PM, AVI-crak said: Вот специально для полной атомарности придумали FIFO с двумя указателями, без блокирования прерываний танцев с бубном. Два потока могут общаться через fifo, даже если выполняются на разных ядрах, одновременно. А посчитать свободное место или остаток - можно в любое время с любой стороны, и при этом не будет ошибок!!! Причём на FIFO можно натравить дма, оно конечно не полностью автоматически получится - но телодвижений будет на пару порядков меньше. Насчёт третьего пункта - не понимаю как и в чём оно должно вам помогать. FIFO - это не синхронный механизм связи, и уж точно не является объектом распространения зоны видимости, он всегда сам по себе - между двумя фиксированными потоками. Когда желающих больше - нужно либо больше разных FIFO, либо канальный уровень сверху, ну или арбитраж ресурсов. Но самого механизма FIFO - это вообще никак не касается, его дело простое - рулить буфером. Кстати я уже давно заметил, чем алгоритм проще - тем надёжнее работает. Как двинуть указатель атомарно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
x893 60 9 июня, 2021 Опубликовано 9 июня, 2021 · Жалоба 13 minutes ago, KnightIgor said: Как двинуть указатель атомарно? А чем не устраивает disable/enable irq ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 9 июня, 2021 Опубликовано 9 июня, 2021 (изменено) · Жалоба 6 minutes ago, x893 said: А чем не устраивает disable/enable irq ? Даже не смешно. Я писал: "2. У меня не просто FIFO, но с атомарным доступом, который достигается флагами и основан на свойстве прерываний в 8051 и CMx, когда их можно, скажем так, отложить. При этом не нужно запрещать/разрешать прерывания глобально ( __enable_irq(), __disable_irq()) ". Конечно, чтобы двигать указатели/счетчик ВНЕ прерывания, я флаг устанавливаю, отмечая критическую секцию. В самом прерывании этот флаг анализируется и прерывание откладывается. Когда критическая секция завершается, она прерывание просто (пере-)разрешает. Происходит влет в прерывание и работа уже с новыми значениями указателей/счетчиков. То есть, запрет прерывания есть, но он происходит внутри самого прерывания, а не в синхронной части программы как бы извне. Изменено 9 июня, 2021 пользователем KnightIgor Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 9 июня, 2021 Опубликовано 9 июня, 2021 · Жалоба 17 минут назад, KnightIgor сказал: Как двинуть указатель атомарно? Зачем? Для случая если только один писатель и только один читатель, это не нужно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 9 июня, 2021 Опубликовано 9 июня, 2021 · Жалоба 8 minutes ago, jcxz said: Зачем? Для случая если только один писатель и только один читатель, это не нужно. например, читает прерывание, а пишет синхронный цикл. Что будет, если синхронный цикл выполняет ldr r0,[r1] add r0,#1 str r0,[r1], а прямо перед str рубануло прерывание, которое использует то, куда указывает [r1]? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 9 июня, 2021 Опубликовано 9 июня, 2021 · Жалоба 1 минуту назад, KnightIgor сказал: а прямо перед str рубануло прерывание, которое использует то, куда указывает [r1]? Нормально всё будет. Если правильно реализовать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KnightIgor 2 9 июня, 2021 Опубликовано 9 июня, 2021 · Жалоба 8 minutes ago, jcxz said: Нормально всё будет. Если правильно реализовать. Вот я уже заинтригован. Это в 8051 была команда xch, которая атомарная. В кортексе такого нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 9 июня, 2021 Опубликовано 9 июня, 2021 · Жалоба 46 minutes ago, KnightIgor said: Конечно, чтобы двигать указатели/счетчик ВНЕ прерывания, я флаг устанавливаю, отмечая критическую секцию. Где все это в коде? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 9 июня, 2021 Опубликовано 9 июня, 2021 · Жалоба 34 минуты назад, KnightIgor сказал: Вот я уже заинтригован. Это в 8051 была команда xch, которая атомарная. В кортексе такого нет. Не нужны атомарные команды чтения-модификации-записи для кольцевого буфера с одним писателем и одним читателем. От слова совсем. Ниже пример одной из реализаций универсальных Fifo у меня (ARM). .h-файл: Скрытый текст class Fifo { protected: volatile u16 rpos, wpos; void *buf; u16 size; public: size_t noEmpty() const { size_t i = wpos; return rpos - i; } size_t noFull() const; size_t cnt() const; size_t free() const; void purge() { rpos = wpos; } void ini(void *b, size_t siz) { buf = b; size = siz; rpos = wpos = 0; } Fifo(void *b, size_t siz) { ini(b, siz); } Fifo() {} }; #define CreateClassFifo(clas, typ, typi, typo) \ class clas : public Fifo { \ public: \ size_t write(typi); \ typo read(); \ typo first() const { \ size_t p = rpos; \ return (p == wpos) ? (typo)-1: (typo)((typ *)buf)[p]; } \ clas(typ *b, size_t siz) : Fifo(b, siz) {} \ clas() {} \ } CreateClassFifo(Fifo8, u8, s32, s32); CreateClassFifo(Fifo16, u16, s32, s32); CreateClassFifo(Fifo32, u32, s32, s64); CreateClassFifo(Fifo64, u64, s64, s64); .cpp файл: Скрытый текст size_t Fifo::noFull() const { size_t i; if (!(i = wpos)) i = size; return i - 1 - rpos; } size_t Fifo::cnt() const { int i = rpos; if ((i -= wpos) < 0) i += size; return i; } size_t Fifo::free() const { int i = wpos; if ((i -= rpos) <= 0) i += size; return i - 1; } //Шаблон создания класса очереди #define FifoReadWrite(clas, typ, typi, typo) \ typo clas::read() \ { \ typo i; \ size_t j = rpos; \ if (i = j - wpos) { \ i = ((typ *)buf)[j] + 1; \ rpos = ((j) ? j: size) - 1; \ } \ return i - 1; \ } \ size_t clas::write(typi c) \ { \ size_t i, i1, i2; \ if (!(i1 = i2 = wpos)) i1 = size; \ if (i = (--i1 - rpos)) { \ ((typ *)buf)[i2] = c; \ wpos = i1; \ } \ return i; \ } FifoReadWrite(Fifo8, u8, s32, s32) FifoReadWrite(Fifo16, u16, s32, s32) FifoReadWrite(Fifo32, u32, s32, s64) FifoReadWrite(Fifo64, u64, s64, s64) Использование: //создание объекта Fifo для (100-1) 8-разрядных элементов #define ncell(m) (sizeof(m) / sizeof((m)[0])) static u8 fifoBuf[100]; Fifo8 fifoQ(fifoBuf, ncell(fifoBuf)); //запись-чтение fifoQ.write(x); int x = fifoQ.read(); PS: Атомарные здесь должны быть только операции сохранения индексов rpos, wpos. А они в ARM атомарны для типов u8/u16/u32. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться