こんにちは、S32K144 ボードで SPI 割り込み通信を設定するときに問題が発生しています。このプロジェクトは PC33771B デバイスとの通信を目的としていますが、現時点では 33664EVB によって提供される一種のループバックになっています。
大部分は機能しているように見えますが、データが実際にバッファー内に保存される方法は奇妙です。5 バイトのメッセージがあり、一般的に次の順序に従います。
B5 0 0 0 B1 B2 B3 B4
LPSPI は単語単位で動作するので、これは正しいはずだと私は思います。しかし、何らかの理由で、常にその順序になるわけではありません。ボードを開始するとき、順序は次のようになる場合があります。
B1 B2 B3 B4 B5 0 0 0
そして時にはそれはただ:
B1 B2 B3 B4 0 0 0 0
5番目のバイトが完全に失われます。
CAN を使用してデバッグできるように、小さなテスト コードを作成しました。必要なメッセージを SPI_1 に送信し、SPI_0 のバッファで終わるメッセージを受信します。何が起こっているかを確認するためにロジック アナライザーも使用しています。
最初のメッセージ:
まず、 spi メッセージは S32K144 規則に従っているSO、5 番目のバイトは CRC になります。また、cmd で 4 番目のバイトにステップインしているので、都合よく 4 に設定しました。SPI_0 が再び準備完了するまで待っても、常にゼロが返されます。これは最初の場合にのみ発生します。
2番目のメッセージ:
最後のバイトはまったく表示されません。何らかの理由で失われたのかもしれませんが、その場合でも、MSB 順に並べられている場合、他の 4 バイトは最初のワードには含まれないはずです。
3番目のメッセージ:
これは意図したとおりに機能しているようで、すべてのデータが取得され、予想どおりの順序で実行されます。落ち着いた後にすべてのメッセージで一貫して受け取るものなので、これは予想される順序だと思います。
これに関する問題は、必ずしも 3 番目のメッセージが適切であるとは限らず、5 番目または 6 番目のメッセージが適切である場合もあれば、5 番目のバイトがまったく表示されない場合や、2 番目のワードに表示される場合もあることです。一度正しく実行し始めると、一貫して動作します。この問題の原因について何かアイデアはありますか?コードと構成は以下の通りです。
void response420 ( zc_can_packet * パケット){
zc_spi_transfer(&spi_rx, &spi_to_can_packet);
transfer_E2E_spi_packet(&E2E_spi, & can_to_spi_packet , &packet-> temp_data [0]);
memcpy (&can_response. temp_data , spi_to_can_packet. rx_buffer , 8);
zc_can_send(&can, &can_response, MAILBOX_0);
}
void zc_spi_transfer ( zc_spi_hw * hw_config, zc_spi_packet * パケット){
hw_config->転送されたパケット= パケット;
hw_config-> hw_mode == MASTER の場合{
SPI_MasterTransfer (hw_config-> inst 、packet-> tx_buffer 、packet-> rx_buffer 、(packet-> message_bytes_length *NUMBER_OF_BITS_IN_BYTE)/hw_config-> master_config -> frameSize );
}それ以外{
SPI_SlaveTransfer (hw_config-> inst 、packet-> tx_buffer 、packet-> rx_buffer 、(packet-> message_bytes_length *NUMBER_OF_BITS_IN_BYTE)/hw_config-> slave_config -> frameSize );
}
}
void transfer_E2E_spi_packet ( E2E_spi_handler * E2E_spi, E2E_spi_packet * パケット, uint8_t * データ){
E2E_spi-> protector_handler -> protect_package (E2E_spi-> protector_handler 、データ、パケット-> packet_data . data_length_bytes 、
&(packet-> raw_spi_packet . tx_buffer [0]), packet-> packet_data . E2E_packet_id , packet-> packet_data . counter );
zc_spi_transfer(E2E_spi-> spi_handler 、&(packet-> raw_spi_packet ));
packet-> packet_data . counter ++; //これは実際にはこのCRC形式では使用されませんが、この関数は複数のCRC形式で動作します
if (packet-> packet_data . counter > E2E_spi-> protector_handler -> counter_overflow_number ){packet-> packet_data . counter = 0;}
}
response420 関数は、CAN コールバック自体によってフラグが立てられたときにメイン内部で呼び出される、CAN パケットを受信するための「コールバック」です。CAN 部分はそれほど重要ではありません。このバグは CAN がなくても発生するため、デバッガーでこのバグが表示された後、より多くの入力をテストできるように CAN を試しました。
一般的に、SPI_SlaveTransfer および SPI_Master 転送関数に見られるように、私は PAL を使用しています。これは PAL 構成です:
SPI_1 設定:
{
.ボーレート = 2000000U、
.frameSize = 40U、
.bitOrder = SPI_TRANSFER_MSB_FIRST 、
.clockPolarity = SPI_ACTIVE_HIGH 、
.ssPolarity = SPI_ACTIVE_LOW 、
.clockPhase = READ_ON_EVEN_EDGE 、
.ssPin = 0,
.transferType = SPI_USING_INTERRUPTS 、
.rxDMAChannel = 0U、
.txDMAチャネル = 0U、
.callback = NULL、
.callbackParam = NULL、
.拡張子 = NULL
}
SPI_0 設定:
{
.frameSize = 40U、
.bitOrder = SPI_TRANSFER_MSB_FIRST 、
.clockPolarity = SPI_ACTIVE_HIGH 、
.ssPolarity = SPI_ACTIVE_LOW 、
.clockPhase = READ_ON_EVEN_EDGE 、
.transferType = SPI_USING_INTERRUPTS 、
.rxDMAChannel = 0U、
.txDMAチャネル = 0U、
.callback = NULL、
.callbackParam = NULL、
.拡張子 = NULL
}
同様の問題を発見した人はいますか?
わかりました。それはよかったです。@danielmartynekさん、本当にありがとう!
素晴らしい。今は期待通りに動作しているようです。
HW はバイトスワッピングをサポートしていますが、SDK ドライバはサポートしていません。
さて、コードを最大限に簡略化しました。
uint8_t送信データ[8] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8};
uint8_t受信データ[8];
lpspi_state_t lpspiState;
int main (){
zc_clock_init();
zc_start_scheduler();
const clock_names_tクロック名[LPSPI_INSTANCE_COUNT] = FEATURE_LPSPI_CLOCKS_NAMES;
clock_names_tクロック名 = クロック名[1];
lpspi_master_config_t spiConfig = {
.bitcount = 8U、
.bitsPerSec = 20000000,
.callback = NULL、
.callbackParam = NULL、
.clkPhase = 1,
.clkPolarity = 0,
.isPcsContinuous = true 、
.lpspiSrcClk = クロック名、
.lsbFirst = false、
.pcsPolarity = 0,
.rxDMAチャネル = 0,
.transferType = LPSPI_USING_INTERRUPTS、
.txDMAチャネル = 0,
.whichPcs = 0,
};
LPSPI_DRV_MasterInit(1, &lpspiState, &spiConfig);
config_spi_pinout(spi_pinoutconfigs[1] .pinout );
一方、 (1){
LPSPI_DRV_MasterTransfer(1, &送信データ[0], &受信データ[0], 8);
zc_delay_milliseconds(1000);
}
0を返します。
}
これを実行してビットカウントを 8 にすると、結果は次のようになります。
間隔が問題だが、少なくともほぼ期待通りに動作する。
ビットカウント32の場合も同様です。
各ワード内のバイトは逆順にされます...
最後に、bitcount 64 で同じことを実行して何が起こるかを確認します。
同じことです。
これを uint8_t 配列ではなく word 配列に配置するとどうなるでしょうか?
uint32_t送信データ[2] = {0x01020304, 0x05060708};
uint8_t受信データ[8];
lpspi_state_t lpspiState;
int main (){
zc_clock_init();
zc_start_scheduler();
const clock_names_tクロック名[LPSPI_INSTANCE_COUNT] = FEATURE_LPSPI_CLOCKS_NAMES;
clock_names_tクロック名 = クロック名[1];
lpspi_master_config_t spiConfig = {
.bitcount = 64U、
.bitsPerSec = 20000000,
.callback = NULL、
.callbackParam = NULL、
.clkPhase = 1,
.clkPolarity = 0,
.isPcsContinuous = true、
.lpspiSrcClk = クロック名、
.lsbFirst = false、
.pcsPolarity = 0,
.rxDMAチャネル = 0,
.transferType = LPSPI_USING_INTERRUPTS、
.txDMAチャネル = 0,
.whichPcs = 0,
};
LPSPI_DRV_MasterInit(1, &lpspiState, &spiConfig);
config_spi_pinout(spi_pinoutconfigs[1] .pinout );
一方、 (1){
LPSPI_DRV_MasterTransfer(1, ( uint8_t *) &送信データ[0], &受信データ[0], 8);
zc_delay_milliseconds(1000);
}
0を返します。
}
実際に動作します...
SO、フレーム サイズ 8 で作業していない場合は、リトルエンディアンのワード単位で送信されるようです。エンディアンを変更する方法はありますか?
こんにちは@danielmartynek
私はすでにuint8_t配列を使用しています
こんにちは@rchust 、
tx_buffer をどのように定義しますか?
ドライバは、8 ビット配列への 8 ビット ポインターを必要とします (LPSPI_DRV_MasterTransfer() 内)。
SO、CANそこに単語を渡す代わりにuint8_t[5] tx_bufferを使用できますか?
よろしくお願い申し上げます。
こんにちは@danielmartynek 、
8 ビット フレームでテストしたところ、バイトを順番に送信して正常に動作しました。しかし、問題が 2 つあります。
1 つ目は、8 ビット フレームの場合、ハードウェアがデータをバイト単位で分割することです。これはフレームの定義なので当然のことですが、FUTURE に問題が発生する可能性があります。PC33771 がそのような間隔のメッセージを受け入れるかどうかはまだテストしていません。そうなるはずですが、期待通りのものではありません。
2 番目 (まだ PC33771 でテストしていない理由) は、PAL ライブラリでは連続モードを true に設定できないことです。PAL ライブラリの「方法」Master_init は、それをLPSPI_DRV_MasterInit に渡す前に、これを false に設定します。
status_t SPI_MasterInit ( const spi_instance_t * constインスタンス、 const spi_master_t *config)
{
status_tステータス = STATUS_ERROR ;
uint8_tインデックス = 0;
/* LPSPI 上で SPI PAL を定義する */
#if (定義済み (SPI_OVER_LPSPI))
/*! @brief LPSPIのクロック名 */
const clock_names_t g_lpspiClock[LPSPI_INSTANCE_COUNT] = FEATURE_LPSPI_CLOCKS_NAMES
if (インスタンス-> instType == SPI_INST_TYPE_LPSPI )
{
lpspi_master_config_t lpspiConfig;
lpspiConfig. bitsPerSec = config-> baudRate ;
lpspiConfig.whichPcs = ( lpspi_which_pcs_t )config-> ssPin ;
lpspiConfig. pcsPolarity = ( lpspi_signal_polarity_t )(!(bool)(config-> ssPolarity ));
lpspiConfig. bitcount = config-> frameSize ;
( void )CLOCK_SYS_GetFreq(g_lpspiClock[( uint32_t )instance-> instIdx ] ,&lpspiConfig.lpspiSrcClk ) ;
lpspiConfig. clkPhase = ( lpspi_clock_phase_t )config-> clockPhase ;
lpspiConfig. clkPolarity = ( lpspi_sck_polarity_t )config-> clockPolarity ;
lpspiConfig. lsbFirst = config-> bitOrder ;
lpspiConfig. transferType = ( lpspi_transfer_type )config-> transferType ;
lpspiConfig. rxDMAChannel = config-> rxDMAChannel ;
lpspiConfig. txDMAChannel = config-> txDMAChannel ;
lpspiConfig.callback = config- > callback ;
lpspiConfig. callbackParam = config-> callbackParam ;
lpspiConfig.isPcsContinuous = false ;
/* このインスタンスにLPSPI状態構造体の1つを割り当てます */
インデックス = SpiAllocateState (LpspiStateIsAllocated、LpspiStateInstanceMapping、インスタンス-> instIdx 、NO_OF_LPSPI_INSTS_FOR_SPI);
ステータス = LPSPI_DRV_MasterInit(インスタンス-> instIdx 、( lpspi_state_t *)(&LpspiState[index])、&lpspiConfig);
}
そうでない場合、
#endif
連続モードでテストする前に、すべてのライブラリを変更して、PAL の使用を停止し、DRV の方法の使用を開始する必要があります。SOて結果を更新しますが、8 ビット フレームで正しい順序で送信されるようです。ただし、40 ビット フレームではそれが実現されないのはまだイライラします。
こんにちは@rchust 、
更新ありがとうございます。
tx_buffer に 8 ビット配列を CAN 使用しますか?
はい、いくつかテストした後、問題の根本を見つけることができました。
どうやら、CAN を使用していないときでもピンを設定していたようで、1 つのピンがマスターの CS と衝突したようです。どうして 1 つのことが別のことに終わるのかはわかりませんが、CAN 構成を削除した後、ほとんどの問題は解消されましたが、1 つだけ問題がありました。
何らかの理由で、8 ビットを超えるフレームでデータを送信すると、各ワード内のバイトが入れ替わります。0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 というデータを含む 64 ビット フレームを配置すると、0x04 0x03 0x02 0x01 0x8 0x07 0x06 0x05 になります。これは、SPI が内部的にワードで動作し、データをバイトごとに入力しているためと思われます。あるいはそれはパルライブラリかもしれません。
こんにちは@danielmartynek 、
まずおっしゃる通り、私の IDE バージョン、SDK は 4.0.2 です。申し訳ありません。
私が示しているコードは CAN コールバックであり、CAN データを SPI バッファにコピーします。このコードは、カスタム ライブラリに組み込もうとしているためこのようになっていますが、実際には、CAN から読み取った内容を SPI (SPI1) に送信し、スレーブ (SPI0) が読み取った内容を CAN に送信するだけです。
CAN は 4 バイトを送信し、次に保護によって CRC である最後のバイトが追加されます。SO SPI は 5 を送信し、次に 5 を読み取り、その後 CAN はバッファの最初の 8 バイト内にあるものをそのまま送信します。バッファ自体は実際にはもっと大きいのですが、 SPI_MasterTransfer はバッファの最初の 5 バイトだけを送信します。
デバッグモードで確認したところ、 SPI_MasterTransfer 内では送信中の SPI は常に期待通りの順序で、ギャップなくバイトが送信されています。常に正しく(少なくとも一貫性を持って)送信されているように見える、SO 問題はスレーブの受信にあるようです。
マスター ブロッキングでも同じ問題が発生するようです。スレーブをブロックするとマスターの送信がブロックされるため、スレーブをブロックして確認することはできません。また、マスターとスレーブの両方のクロック極性を低く設定すると、多くの上位ビットが失われることもわかりましたが、まずは最初のメッセージの受信が機能しない問題に取り組みましょう。
こんにちは@rchust 、
SDKs ではなく IDEs (3.6.2) を指定したようです。
リリース番号がわかれば、報告されたバグを確認CANます。
非ブロッキング方法を使用しているようですが、ブロッキング転送関数でテストできますか?
コードはあまり読みやすくありません。
伝達関数の引数としてどのような値を置きますか?
バッファをどうやって埋めるのですか?
SPI 通信で観察されるギャップは、ドライバのオーバーヘッドによって発生します。ドライバは送信 FIFO に十分な速さでデータを入れることができません。8 ビット モードでは、ドライバは FIFO にデータを 1 バイトずつ書き込むため、連続した書き込みの間にレイテンシが発生します。この遅延は、SPI クロック速度が高くなると顕著になります。この問題を軽減するには、DMA を使用することをお勧めします。
よろしくお願いいたします。
ダニエル
こんにちは、ダニエル。
私のSDKは3.6.2です。私は 33664EVB ボードとその TPL を介して SPI を使用しており、チップ セレクトは使用していません。チャネルはそれぞれ SPI1_clock、SPI1_tx、TPL1_data、TPL1_clock です。混乱を避けるために、FUTUREの画像では名前を付けます。後者の 2 つを SPI0_rx と SPI0_clock に直接入力してテストしたところ、同じ結果が示されたことを指摘しておきます。
8 ビット モードでテストしたところ、次の結果が得られました。
最初のメッセージ:
4番目のメッセージ:
最初に気づくのは、最初の単語と 2 番目の単語の間にある大きなギャップです。より大きなメッセージでもテストしましたが、8 ビットを使用すると各単語間にギャップが生じます。周波数を下げてみると、ギャップは減少し、500kHz あたりで消えます。それでも、33664EVB および 3771 のアプリケーション ノートでは 2MHz の使用が推奨されており、一般的に速度が低いことは望ましくありません。
まったく同じではありませんが、問題は依然として似ています。最初は最後のバイトはまったく表示されませんが、次にそれが最初に表示され、その後に他のバイトが正しい順序で表示されます。また、8 ビットではデータが入力した順序で送信されますが、40 ビット モードでは信号内のデータが交換され、その後スレーブによって再度交換されることも指摘しておく価値があります。
ワード間の大きなギャップがなければ 8 ビットの方が望ましいのですが、それでも問題は発生します。8ビット500kHzの場合:
最初のメッセージ:
2番目のメッセージ:
3 番目のメッセージSO:
これは 2 つの問題を示しています。1 つ目は私が言及しているスレーブによって読み取られたデータの不一致に関する問題であり、次に TPL のクロックを見ると 2 つ目の問題がわかります。TPL はパルス幅を 2MHz のように維持します。それがそのスピードが必要な理由の一つです。
こんにちは@rchust 、
ドライバのバージョンを指定できますか?
どのようなプロトコルを使用していますか?チップセレクト信号を使用していますか?
ロジック アナライザのキャプチャでチャネルにラベルを付けることはできますか?
LPSPI ハードウェアは 8 ビット フレームの連続送信をサポートしており、当社のソフトウェア ドライバーはこれと互換性があります。
8 ビットのデータを FIFO に配置することで、40 ビットのフレームを連続モードで送信CAN。
また、タイミングや信号の整合性に関連する潜在的な問題を排除するために、より低いボー レートで SPI 通信をテストしてみてください。
よろしくお願いいたします。
ダニエル