/** * @file * @brief SPI通信(Master側)のHALです。 * @note SPI HALは、 * SPIポートの初期化、データ送信、データ受信を行う、 * SPI通信の抽象化レイヤです。 * 個々の機器でこのインターフェースを実装して使用します。 */ #ifndef SPI_H_ #define SPI_H_ #include /** * @enum SPI_MODE * @brief SPI動作モードの設定 * @note 型はuint8_tを想定 */ typedef enum { SPI_MODE_0 = 0, //!< CPOL=0, CPHA = 0 SPI_MODE_1 = 1, //!< CPOL=0, CPHA = 1 SPI_MODE_2 = 2, //!< CPOL=1, CPHA = 0 SPI_MODE_3 = 3 //!< CPOL=1, CPHA = 1 } SPI_MODE; /** * @enum SPI_MODE * @brief SPI動作モードの設定 * @note 型はuint8_tを想定 */ typedef enum { SPI_CS_STATE_AFTER_TX_HIGH = 0, //!< 送信後にCSをHighにする SPI_CS_STATE_AFTER_TX_LOW = 1 //!< 送信後にCSをLowのままにし、そのまま受信動作などを行う } SPI_CS_STATE_AFTER_TX; /** * @struct SPI_Config * @brief SPIポートの初期化、データ送信・受信の際に必要となる設定情報を格納する構造体です。 */ typedef struct { uint8_t comm_ch; //!< 継承先の機器がつながっている通信ポート番号 uint8_t gpio_ch; //!< 継承先の機器がつながっているChip Select用GPIOポート番号 uint32_t frequency_khz; //!< SPIクロックの周波数 単位:kHz SPI_MODE mode; //!< SPI動作モード uint8_t tx_data_for_rx; //!< RX動作をするために定期的に送るTXデータ uint16_t rx_length; //!< 受信するデータ数、受信動作前に設定する SPI_CS_STATE_AFTER_TX cs_state_after_tx; //!< 送信動作後にChip SelectをHighにするかどうかのフラグ } SPI_Config; /** * @enum SPI_ERR_CODE * @brief SPI用の汎用エラーコード * @note 型はint8_tを想定しているが, if_listでラップされているためSPIの公開関数の返り値はintとなっている * 基本負なのはRXの返り値は正が送ったByte数, 負がエラーコードとなっているため */ typedef enum { SPI_ERR_UNKNOWN = -20, //!< 原因不明 SPI_ERR_RX_BUFFER_SMALL = -14, //!< 受信バッファサイズが受信データ長より小さい SPI_ERR_DATA_NEGA = -13, //!< 送受信データサイズが負のエラー SPI_ERR_DATA_LARGE = -12, //!< 送受信データサイズが大きすぎる SPI_ERR_GPIO = -5, //!< GPIO関連エラー SPI_ERR_YET = -4, //!< チャンネル未オープン SPI_ERR_ALREADY = -3, //!< チャンネルオープン済み SPI_ERR_FREQUENCY = -2, //!< 周波数異常 SPI_ERR_CH = -1, //!< チャンネル異常 (Port_configに無い) SPI_ERR_OK = 0 //!< OKは0を踏襲 } SPI_ERR_CODE; /** * @brief SPI_Config構造体をグローバルインスタンスとして定義し、ポインタを渡すことでポートを初期化します。 * @param[in] my_spi_v 初期化するSPI_Config構造体へのポインタ * @return int SPI_ERR_CODEとしたいが, if_listでintと統一されている。 * @note SPI通信ラッパーのクラスを使用する時は起動時に必ず実施してください。 * この関数を実行する前にSPI_Config構造体内の設定値を設定しておく必要があります。 */ int SPI_init(void* my_spi_v); /** * @brief SPI_Config構造体にて指定されたchからデータを受信します * @param[in] my_spi_v : 対象とするSPI_Config構造体へのポインタ * @param[out] data_v : 受信データ格納先へのポインタ * @param[in] buffer_size : 受信データ格納先のバッファサイズ、SPI通信による受信データ長よりも長い必要がある * @retval 0: 受信データなし * @retval 正: 受信データバイト数 * @retval 負: エラー. SPI_ERR_CODE に従う * @note この関数内でSPI読み出し要求を送信しています */ int SPI_rx(void* my_spi_v, void* data_v, int buffer_size); /** * @brief SPI_Config構造体にて指定されたchへデータを送信します * @param[in] my_spi_v : 対象とするSPI_Config構造体へのポインタ * @param[in] data_v : 送信データ格納先へのポインタ * @param[in] count : 送信データサイズ * @return int: SPI_ERR_CODE に従う */ int SPI_tx(void* my_spi_v, void* data_v, int data_size); /** * @brief 指定されたchを開きなおす * @param[in] my_spi_v 開きなおす際のポート設定 * @param[in] reason reopenする理由.0は正常操作を示す TODO: reasonのenumを作る? * @return int: SPI_ERR_CODE に従う */ int SPI_reopen(void* my_spi_v, int reason); /** * @brief rx_lengthを設定する * @param[in] my_spi_v : 対象とするSPI_Config構造体へのポインタ * @param[in] rx_length : 設定する受信データ長 * @return なし */ void SPI_set_rx_length(void* my_spi_v, const uint16_t rx_length); /** * @brief cs_state_after_txを設定する * @param[in] my_spi_v : 対象とするSPI_Config構造体へのポインタ * @param[in] cs_state_after_tx : 設定するcs_state_after_tx * @return なし */ void SPI_set_cs_state_after_tx(void* my_spi_v, const SPI_CS_STATE_AFTER_TX cs_state_after_tx); #endif