痞子衡嵌入式:常用的資料差錯控制技術(1)- 重複校驗(Repetition Code)

痞子衡發表於2017-09-02

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家講的是嵌入式裡資料差錯控制技術-重複校驗

  在嵌入式應用裡,除了最核心的資料處理外,我們還會經常和資料傳輸打交道。資料傳輸需要硬體傳輸介面的支援,序列介面由於佔用引腳少的優點目前應用比並行介面廣泛,常用的序列介面種類非常多,比如UART,SPI,I2C,USB等,在使用這些介面傳輸資料時避不可免會遇到一個問題,如果傳輸過程中遇到未知硬體干擾發生bit錯誤怎麼辦?

  痞子衡今天給大家講的就是資料傳輸過程中用於差錯檢測的最簡單的方法,即重複校驗法。

一、重複校驗法基本原理

1.1 校驗依據

  重複校驗法的校驗依據就是判斷重複傳輸的q組n bits二進位制資料是否一致。

1.2 重複校驗位

  為了實現重複校驗,就是不斷重複傳輸這組n bits原始資料q次即可,一次校驗的q*n bits資料塊中,僅有n bits資料是原始有效資料,校驗位就是那些重複的(q-1)*n bits資料。是不是覺得簡單又粗暴?

1.3 校驗方法

  假設原始資料塊是X[n-1:0]共n bits,重複次數為q(q一般為奇數),按重複傳輸方式,可分為兩個子類:

  • 按bit重複:傳送資料序列為,q個X0(X0X0...),q個X1(X1X1...)...,q個Xn-1(Xn-1Xn-1...)
  • 按block重複:傳送資料序列為,第1個X[n-1:0],第2個X[n-1:0]...,第q個X[n-1:0]。

  接受端收到資料後,逐次比較q個重複位,如完全一致,則認為沒有錯差;如不一致,則存在錯誤bit。如需糾錯的話,原理也很簡單,判斷q個重複位裡哪種資料位出現的次數多(這裡解釋了q為何應是奇數)則為原始正確資料位。

1.4 C程式碼實現

  實際中按block重複校驗法應用比較多,此處示例程式碼以此為例:

安裝包:codeblocks-17.12mingw-setup.exe
整合環境:CodeBlocks 17.12 rev 11256
編譯器:GNU GCC 5.1.0
偵錯程式:GNU gdb (GDB) 7.9.1

// repetition_code.c
//////////////////////////////////////////////////////////
#include <stdint.h>
#include <assert.h>

/*!
 * @brief 處理按block重複的資料塊
 *
 * @param src, 待處理的資料塊.
 * @param dest, 處理完成的原始資料.
 * @param lenInBytes, 待處理的資料塊長度.
 * @param repeatTimes, 資料重複次數(假定為奇數).
 * @retval 0, 資料無錯誤位.
 * @retval 1, 資料有錯誤位且已糾正.
 */
uint32_t verify_correct_repetition_block(uint8_t *src,
                                         uint8_t *dest,
                                         uint32_t lenInBytes,
                                         uint32_t repeatTimes)
{
    assert(repeatTimes % 2);
    assert(!(lenInBytes % repeatTimes));

    uint32_t result = 0;
    uint32_t blockBytes = lenInBytes / repeatTimes;

    // 遍歷一個block長度裡每個byte
    for (uint32_t i = 0; i < blockBytes; i++)
    {
        // 遍歷當前byte的每個bit
        uint8_t correctByte = 0;
        for (uint32_t j = 0; j < 8; j++)
        {
            // 遍歷當前byte的所有重複byte
            uint32_t bit1Count = 0;
            for (uint32_t k = 0; k < repeatTimes; k++)
            {
                // 記錄所有重複byte中當前bit為1的個數
                uint8_t countByte = *(src + i + k * blockBytes);
                bit1Count += (countByte & (0x1u << j)) >> j;
            }
            // 當bit1出現半數則將當前bit認定為1
            if (bit1Count > (repeatTimes / 2))
            {
                correctByte |= 0x1u << j;
            }
            // 首次發現錯誤bit時,置位result
            if ((!result) && (bit1Count !=0) && bit1Count != repeatTimes)
            {
                result = 1;
            }
        }
        // 將校驗後的byte存入dest
        *(dest + i) = correctByte;
    }

    return result;
}

// main.c
//////////////////////////////////////////////////////////
#include "repetition_code.h"
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    uint8_t src[3][4] = {{0x32, 0x33, 0x04, 0x08},
                         {0x32, 0x83, 0x04, 0xd8},
                         {0x31, 0x33, 0x04, 0xe8}};
    uint8_t dest[4];
    uint32_t result = verify_correct_repetition_block((uint8_t *)src, dest, sizeof(src), sizeof(src) / sizeof(src[0]));

    printf("result = %d\n", result);
    for (uint32_t i = 0; i < sizeof(dest); i++)
    {
        printf("dest[%d] = 0x%x\n", i, dest[i]);
    }
    return 0;
}

1.5 行業應用

  實際上本文所講的單純的重複校驗法行業因為效率的原因,行業裡較少應用,其改進版的實現RA Codes應用在了FlexRay協議裡。

二、重複校驗法失效分析

  重複校驗實現非常簡單,具有比較理想的檢錯能力,但效率太低,並未得到廣泛使用。即便犧牲了效率,但重複校驗法也存在如下2個缺陷,導致其檢錯糾錯並不可靠:

  • 當重複bit全部發生錯誤時,會被誤認為沒有錯誤bit發生。
  • 當錯誤bit出現概率大於原始bit時,在糾錯時會認定錯誤bit是原始bit。

  有沒有其他比重複校驗法更高效的檢錯方法?痞子衡在下篇會繼續聊。

  至此,嵌入式裡資料差錯控制技術之重複校驗痞子衡便介紹完畢了,掌聲在哪裡~~~

相關文章