zoukankan      html  css  js  c++  java
  • STM32 & FreeRTOS & KFIFO (巧夺天工)

    巧夺天工 的 KFIFO ,用STM32实现。

    实现源文件如下:

    /**********************************************************
      *
      *  文件名:    kfifo.c
      *
      *  文件描述:    该文件包含的kfifo的处理函数
      *
      *  创建人:       GXP
      *
      *   创建日期:     2016年8月9日16:13:06
      *
      *  版本号:    1.0
      *
      *  修改记录:    无
        *   
        *   本文参考博客地址: http://blog.csdn.net/linyt/article/details/5764312
        *                     http://blog.csdn.net/chen19870707/article/details/39899743
      *
    ***********************************************************/
    
    
    #include "kfifo.h"
    
    #include "FreeRTOS.h"
    #include "task.h"
    
    
    #define min(a, b)                (((a) < (b)) ? (a) : (b))
    
    
    
    //找出最接近 最大2的指数次幂
    unsigned int roundup_pow_of_two(unsigned int date_roundup_pow_of_two )
    {            
        /* 这里采用 STM32 硬件提供的计算前导零指令 CLZ
         * 举个例子,假如变量date_roundup_pow_of_two 0x09
         *(二进制为:0000 0000 0000 0000 0000 0000 0000 1001), 即bit3和bit0为1
         * 则__clz( (date_roundup_pow_of_two)的值为28,即最高位1 前面有28个0,32-28 =3 代表最高位1 的 位置
         * 31UL 表示 无符号 int 数字 31,否则默认为 有符号 int 数字 31
         * 这里参考  FreeRTOS 的 寻找高级优先级任务 的写法,详细解释到朱工博客
         * 博客地址: http://blog.csdn.net/zhzht19861011/article/details/51418383
         */
    
        return ( 1UL << ( 32UL - ( unsigned int ) __clz( (date_roundup_pow_of_two) ) ) );
    
    }
    
    
    /* 
     * 每次调用这个函数都会产生 两个内存块,一个内存块指向struct KFIFO,一个指向 KFIFO.buff
     * 因此 如果这两个内存块不在使用请释放掉!GXP,2016年8月17日12:55:54
     */
    
    struct KFIFO *kfifo_alloc(unsigned int size) 
    {   
        unsigned char *buffer;
        
        struct KFIFO *ret;
        
            ret=(struct KFIFO *) pvPortMalloc(sizeof (struct KFIFO));
    
        /*  
         * round up to the next power of 2, since our 'let the indices  
         * wrap' tachnique works only in this case.  
             * 如果size 是2的 次幂圆整,则 size & (size - 1)  =0
         */
      
        if (size & (size - 1)) 
            {   
                //        BUG_ON(size > 0x80000000);  
                
                //如果你要申请的buffer 不是 2的 次幂圆整,就要把 size 变成 2的次幂圆整 ,方便下面计算
            size = roundup_pow_of_two(size);
        }
            
            //这里使用 FreeRTOS的 分配内存的 API
        buffer = (unsigned char*) pvPortMalloc(size);
            
        if (!buffer)   //如果返回的值为NULL,这说明分配内存失败
            return 0UL;
      
            //    ret = kfifo_init(buffer, size, lock);   
            
            ret->buffer=buffer;
            ret->size  =size;
            ret->in  = 0;
            ret->out = 0;
            
        if (!ret) //如果ret的值为NULL,这说明分配内存失败
            vPortFree(buffer); //释放之前分配的 内存空间
      
        return ret;
            
    }
    
    
    unsigned int __kfifo_put(struct KFIFO *fifo, unsigned char *buffer, unsigned int len)   
    {
        unsigned int L;
        
            //环形缓冲区的剩余容量为fifo->size - fifo->in + fifo->out,让写入的长度取len和剩余容量中较小的,避免写越界;
        len = min( len , fifo->size - fifo->in + fifo->out );
      
        /*  
         * Ensure that we sample the fifo->out index -before- we  
         * start putting bytes into the kfifo.  
         */   
                    //多处理器 处理内存 的 屏障,STM32不需要这个
                    //    smp_mb(); 
      
        /* first put the data starting from fifo->in to buffer end */
                    /* 首先将数据从fifo.in 所在的位置开始写,写之前,首先要看一下fifo->in到 buffer 末尾的大小 是不是 比 len 大*/
        
                    /*
                     * 前面讲到fifo->size已经2的次幂圆整,主要是方便这里计算,提升效率
                 * 在对10进行求余的时候,我们发现,余数总是整数中的个位上的数字,而不用管其他位是什么;
                     * 所以,kfifo->in % kfifo->size 可以转化为 kfifo->in & (kfifo->size – 1),效率会提升
                     * 所以fifo->size - (fifo->in & (fifo->size - L)) 即位 fifo->in 到 buffer末尾所剩余的长度,
                     * L取len和剩余长度的最小值,即为需要拷贝L 字节到fifo->buffer + fifo->in的位置上。
                     */ 
        L = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
        
        memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, L);   
      
        /* then put the rest (if any) at the beginning of the buffer */ 
    
        memcpy(fifo->buffer, buffer + L, len - L);
      
        /*  
         * Ensure that we add the bytes to the kfifo -before-  
         * we update the fifo->in index.  
         */   
      
          // smp_wmb();   //多处理器 处理内存 的 屏障,STM32不需要这个    
    
                /* 
                 * 注意这里 只是用了 fifo->in +=  len而未取模,
                 * 这就是kfifo的设计精妙之处,这里用到了unsigned int的溢出性质,
                 * 当in 持续增加到溢出时又会被置为0,这样就节省了每次in向前增加都要取模的性能,
                 * 锱铢必较,精益求精,让人不得不佩服。
                 */
      
        fifo->in += len; 
            
          /*返回值 代表  写入数据的个数 ,这样 就可以根据返回值 判断缓冲区是否写满*/
        return len;   
    }  
      
    unsigned int __kfifo_get(struct KFIFO *fifo, unsigned char *buffer, unsigned int len)   
    {
        unsigned int L;   
      
        len = min(len, fifo->in - fifo->out);   
      
        /*  
         * Ensure that we sample the fifo->in index -before- we  
         * start removing bytes from the kfifo.  
         */   
      
        //smp_rmb();    //多处理器 处理内存 的 屏障,STM32不需要这个
      
        /* first get the data from fifo->out until the end of the buffer */   
        L = min(len, fifo->size - (fifo->out & (fifo->size - 1)));   
        memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), L);   
      
        /* then get the rest (if any) from the beginning of the buffer */   
        memcpy(buffer + L, fifo->buffer, len - L);   
      
        /*  
         * Ensure that we remove the bytes from the kfifo -before-  
         * we update the fifo->out index.  
         */   
      
        //smp_mb();   //多处理器 处理内存 的 屏障,STM32不需要这个
                
                /*
               * 注意这里 只是用了 fifo->out +=  len 也未取模运算,
                 * 同样unsigned int的溢出性质,当out 持续增加到溢出时又会被置为0,
                 * 如果in先溢出,出现 in  < out 的情况,那么 in – out 为负数(又将溢出),
                 * in – out 的值还是为buffer中数据的长度。
                 */
    
        fifo->out += len;
      
        return len;  
    }

    头文件如下:

    #ifndef _KFIFO_H_
    #define _KFIFO_H
    
    
    //声明 一个 结构体 kfifo
    
    struct KFIFO
    {   
        unsigned char *buffer;    /* the buffer holding the data */   
        unsigned int size;            /* the size of the allocated buffer */   
        unsigned int in;                /* data is added at offset (in % size) */   
        unsigned int out;                /* data is extracted from off. (out % size) */   
            /*STM32 只有一个核心,同一时刻只能写或者读,因此不需要*/
            //    volatile unsigned int *lock; /* protects concurrent modifications */  
    };
    
    unsigned int roundup_pow_of_two( unsigned int date_roundup_pow_of_two );
    
    struct KFIFO *kfifo_alloc(unsigned int size);
    
    unsigned int __kfifo_put(struct KFIFO *fifo, unsigned char *buffer, unsigned int len);
    
    unsigned int __kfifo_get(struct KFIFO *fifo, unsigned char *buffer, unsigned int len);
    
    #endif

    上面  实现 找出  最接近 最大2的指数次幂 的是通过 STM32 一个特殊的 寄存器实现的 ,可以百度 找 C 语言 实现的方式。

    以及内存 的 分配 是由  FreeRTOS提供  的 内存分配和释放  实现的 。

    使用 方式如下:

    //创建一个 KFIFO 的结构体 指针
    
    struct KFIFO *test_kifo_buffer=NULL;
            //kfifo 测试 第一步: 创建 一个 1024字节的 fifo buff
        
                //首先定义一个 在全局变量中定义一个 KFIFO 结构体 test_kifo_buffer
                
                //接着 给这个 KFIFO 结构体 test_kifo_buffer 申请 一个 1024字节的 内存空间
        
        //你如果分配468,会分配512字节的空间,你如果写 668,就会分配1024字节的 空间,1025就分配 2048
        //因为这样 会方便计算
        
        test_kifo_buffer=kfifo_alloc( 668);//这里写入668,也分配的是 1024 字节的 空间
        
        if( !test_kifo_buffer )
                printf("
     KFIFO 结构体 test_kifo_buffer 没有创建成功!
    ");
        //kfifo 测试 第二步: 发送10个字节写入到 KFIFO 结构体 test_kifo_buffer 中
            write_counter=__kfifo_put(test_kifo_buffer, test_fifo_write_buff, 10 );
            
                if(write_counter!=10)
                    printf("
    发送10个字节写入到KFIFO结构体test_kifo_buffer失败,写入个数是:%d.
    ",write_counter);
            read_counter=read_counter=__kfifo_get(test_kifo_buffer, test_fifo_read_buff,5);
            
            printf("从test_kifo_buffer缓冲区读取的数据是%s,读出的个数是%d.
    ",test_fifo_read_buff,read_counter);
            
            printf("test_kifo_buffer->size:%d,test_kifo_buffer->out:%d,test_kifo_buffer->in:%d.
    ",test_kifo_buffer->size,test_kifo_buffer->out,test_kifo_buffer->in);
  • 相关阅读:
    pat 甲级 1065. A+B and C (64bit) (20)
    pat 甲级 1064. Complete Binary Search Tree (30)
    pat 甲级 1010. Radix (25)
    pat 甲级 1009. Product of Polynomials (25)
    pat 甲级 1056. Mice and Rice (25)
    pat 甲级 1078. Hashing (25)
    pat 甲级 1080. Graduate Admission (30)
    pat 甲级 团体天梯 L3-004. 肿瘤诊断
    pat 甲级 1099. Build A Binary Search Tree (30)
    Codeforce 672B. Different is Good
  • 原文地址:https://www.cnblogs.com/suozhang/p/6373510.html
Copyright © 2011-2022 走看看