2

MSP430F5438A 用のファームウェアを書いています。このコードはほとんどが MISRA04 準拠であることを望みます (C90 ではなく C99 を使用しています)。MISRA 準拠をチェックできる IAR 5.51 を使用しています。

次のデータ構造があります。

typedef struct
{
    struct
    {
        uint16_t baud_rate;
        uint8_t data_bits;
        uint8_t parity;
        uint8_t stop_bits;
        uint8_t b_flow_control;
    } serial_settings;
    ...
} config_settings_t;

この構造体のインスタンスを、グローバルに読み取ることができるフラッシュ メモリに作成したいと考えています。フラッシュに書き込むための別の方法が既にあります。

この構造体へのグローバル ポインターの定義は次のとおりです。

volatile config_settings_t *gp_app_config = (uint8_t) 0x1800u;

これは問題なく動作し、MISRA に準拠しているようです。

これで、フラッシュ内の任意のセグメントに対して書き込みおよび読み取りを行う一連の関数をフラッシュ ドライバーに実装しました。それらはすべて uint8_t ポインターを引数として取ります。

このような関数を呼び出すにはどうすればよいですか?

flash_segment_erase(uint8_t * p_flash, uint16_t len);

これ:

flash_erase_check((uint8_t*)gp_app_config, sizeof(config_settings_t));

コンパイルして正常に動作しますが、MISRA04 によるとタブーです...

Error[Pm141]: a cast should not be performed between a pointer to object type and a different pointer to object type, this casts from type "config_settings_t volatile *" to "uint8_t *" (MISRA C 2004 rule 11.4) 

ありがとう、ニック

4

1 に答える 1

2

C99 をサポートしているため、MISRA-C:2012 の使用を検討してください。IAR がサポートしているかどうかはわかりませんが、MISRA-C:2012 はこの春にリリースされました。

MISRA-C:2004 については、考慮すべき点がいくつかあります。


1)

  • グローバル変数の宣言は、MISRA-C 準拠の境界にあります。8.10 と 8.11 の 2 つのルールがあり、ファイル スコープ変数はstatic「外部リンケージが必要でない限り」強制されます。あなたの場合に必要かどうかは少し主観的です。そのポインターがグローバルである必要がある明確な理由はありません。

  • フラッシュ メモリへのポインタを読み書きポインタとして宣言するのは奇妙です。それは意味がありません。

  • config_settings_t への const volatile ポインターが実際には必要なのに、アドレスを uint8_t へのポインターにキャストするのは意味がありません。また、const または volatile キーワードをキャストすることは、ルール 11.5 で禁止されています。

    したがって、それを使用するモジュール内で静的として宣言し、読み取り専用にすることを検討します。次のようにコードを書き直すことを検討してください。

// 何か.h

const volatile config_settings_t* get_app_config (void); 
// use a getter function instead of a global variable

// 何か.c

static const volatile config_settings_t *
  gp_app_config = (const volatile config_settings_t*) 0x1800u;


const volatile config_settings_t* get_app_config (void)
{
  return gp_app_config;
}

また、実際のポインター自体を ROM に保存することも検討してください (そして、その宣言を読むのがさらに「悪」になります...):

static const volatile config_settings_t * const
  gp_app_config = (const volatile config_settings_t*) 0x1800u;

2)

このような関数を呼び出すにはどうすればよいですか?

flash_segment_erase(uint8_t * p_flash, uint16_t len);

すべきではありません。まず、これは NVM プログラミング ドライバーの一部であるため、常に読み取り専用変数を処理します。それらを volatile として宣言する必要はないかもしれませんが、一部のコンパイラではオプティマイザの事故を防ぐことができます。

C では、すべてのワイルド タイプ キャストを使用できます。コードの主な問題は、const と volatile をキャストしていないことです。

また、汎用データをフラッシュにプログラムします。フラッシュ プログラミング ドライバーはバイト レベルで動作する場合がありますが、インターフェイスはそれだけである必要はありませんuint8_t*。に変更するvoid*と、その日が節約され、MISRA ルール 11.2 から節約できます。

関数を次のように宣言する必要があります。

void flash_segment_erase (const volatile void* p_flash, uint16_t len);

これで、 があり、それをジェネリックパラメーターconst volatile config_settings_t*を取る関数に渡したいとします。const volatile void*これは MISRA と完全に互換性があるはずです。


3)

sizeofは型 の変数を生成することに注意してください。size_tこれは、 と完全に互換性があるとは限りませんuint16_tsize_tがたとえば と同等の場合uint32_t、さまざまな MISRA ルールに違反します。したがって、式の目的の型にキャストします。

flash_erase_check (gp_app_config, (uint16_t)sizeof(config_settings_t));

編集: 11.3 や 11.4 など、これらのようなキャストや、整数とポインターの間のキャストを許可しない、さまざまな単純な愚かなルールがあります。これらのルールは、CPU ハードウェア レジスタ、NVM プログラミング、ブート ローダー、MISRA-C からの割り込みベクトル テーブルを効果的に禁止するため、無視する必要があります。そうしないと、MISRA-C は実世界で使用できません。

明らかに、これらのルールは、組込みプログラミングの経験がない一部のデスクトップ プログラマーまたはツール ベンダーが、委員会に対してあまりにも多くの影響力を持っていた結果です (cough-ldra-cough)。多くの MISRA ユーザーの苦情にもかかわらず、MISRA-C:2012 には同じ愚かな勧告ルールが残っています。

于 2013-05-03T14:28:04.377 に答える