2024年10月3日木曜日

STM32 噂通りNOPが効かないCortex-M7というもの

おはよーございます.天気晴れ.少し暑い.

STM32H723に小さなI2C DACを接続して使います.

I2C peripheralを使うのがフツーでしょう.しかしpin配置の自由度が低下するのでperipheralは使わずに、port直叩きでやります.こんな感じで.
static void DAC_clk(void){
    DAC_CK(1);   // port high
    DAC_CK(0);   // port low
}
DACは動くには動くのですが、clk周波数が2.5MHzぐらいと速過ぎます.I2Cって100kHzとか400kHzですよね.

そこでNOPで遅延させたろうと、こうしました.
static void DAC_clk(void){
    DAC_CK(1);
    __asm__("NOP");
    DAC_CK(0);
    __asm__("NOP");
}
しかしNOPが効きません.
Cortex-M7はhardware的にNOPを無視するらしいと聞いてたのですが、噂通り素通りしてるみたいよ.

NOPは諦めて、HAL_Delay()を使うと最短1mSecも遅延しちゃって遅すぎて困ります.

詰みました.
I2C peripheralを使う事にします.プリント基板は書き替えます.

このダラーッとしたかったるさ....

ーーーー
I2CのDMAでトラブル中です.ぜーんぜん動きません.blockingならスイスイ動きます.
void DAC_set(int x){
    uint8_t data[2] ;
    data[0] = 0xaa;
    data[1] = 0x55;
    HAL_I2C_Master_Transmit_DMA( hi2c4, ADRS<1, data, 2 );
}

こちらによると、I2C4のDMAはBDMAというもので、RAM_D3空間にのみアクセスできるらしい.
STM32H7ともなるとバスが複数在る複雑なアーキテクチャになっていて、peripheralが別の空間に置かれてたりする.reference manualを隅々まで読むのダルいのでそんなに読んでません.

さらにこちらによると、RAM_D3空間にアクセスするには、リンカスクリプトに追記しなくちゃいけないんだとか.これを.ldの後ろの方に追加.
.DATA_RAM_D3 (NOLOAD) :
  {
  } >RAM_D3

それでDMAを呼び出すところを、こんな風にすればRAM_D3にdata[2]が配置される.
uint8_t data[2]  __attribute__ ((section (".DATA_RAM_D3")));
void DAC_set(int x){
    data[0] = 0xaa;
    data[1] = 0x55;
    HAL_I2C_Master_Transmit_DMA( hi2c4, ADRS<1, data, 2 );
}

なのだがっ! うごかない~ いや~ん clkすら出てこない~
RAM_D3は正常に読めてるんですがね.
BDMAに起動かかってないのかな?

このダラーッとしたかったるさ....

#I2C4 DMAを断念します

かしこ

8 件のコメント:

  1. >Cortex-M7はhardware的にNOPを無視するらしい
    まぁ、元々、
    ・「NOP」は、「時間調整用の命令」ではない
    ので、「コレが、正しい仕様」ですがね。
    ※いままで「そうしなかった」のは、
    ・既存のソフト資産との、互換性を保つため
    だったんだろうなー。で、もう「アーキテクチャーを刷新」する為に、
    ・「互換性を捨て」て、本来の仕様に戻した
    と言うことなのでしょう。
    ※あと、もう、
    ・イマドキ「アセンブラでチマチマ」ソフトを書く時代ではない
    と言うことなのかも知れません。
    ※「インラインアセンブラ」だって「裏技」なのに、そのうえで
    ・「NOP で時間稼ぎ」なんて「裏技中の裏技」
    ですね(笑)

    >NOPは諦めて、HAL_Delay()を使うと最短1mSecも遅延しちゃって遅すぎて困ります.
    それなら、「タイマ割り込み中」で、clock on/off すれば?、と、思ったのですが、「そんな見通しが悪いソフト」を作る位なら、もう「メーカーが用意したやりかた」を、素直に使ったほうがいいですね・・・
    ※「見通しが悪いソフト」は、後で自分で見ても「何でこんなことしてるんだ!?」に、なる確率が高いし。

    Windows でも、XPあたりまでは、「ソフトディレイ(↑ みたいなやり方)」が、効いたのですが、恐らく Vista あたりから、それだと、
    ・(うまく)動かないソフト
    が、沢山出てきました。まぁ、この辺りは「歴史の必然的な流れ」なんだろうなー

    返信削除
    返信
    1. ほぅ、XPの頃は1chipマイコンみたいで平和(ぴんふ)ですな

      I2C peripheralを実装中なう

      削除
    2. >ほぅ、XPの頃は1chipマイコンみたい
      まぁ、またどうでもいい話ですが、
      ・Android (スマホ)で動く、「XP(以前のOSが動く)エミュレーター」
      とか、あったと思います。
      ※主な用途は「XP(以前のOSの)時代のゲームを、スマホで動かしたい」という、需要がある為です。実際、結構動いてたハズ。
      「Bio_100%」とかのゲームを、「スマホで動かしてる」のが、どっかにあった記憶があります。

      削除
    3. 逆にwin上でandroidを動かすemuもあるんですね
      とくに欲しくはないかもですが

      削除
  2. >STM32H723
    なんと、このICは、
    ・倍精度浮動小数点ユニット内蔵
    なんですね・・・
    ※いわゆる「コプロセッサ」ですが、パソコンのCPUですら、コレが最初に積まれたのが「80486」ですから、もう「とっくの昔に」超えてるってことですね。
    やる気になれば「Windows」とか、動くんだろうな。。。

    返信削除
    返信
    1. おかげで浮動小数点演算がバカみたいに速いです
      整数演算と浮動小数点演算が同じようなもんですから
      らっきぃ~

      削除
  3. >HAL_Delay()を使うと最短1mSecも遅延しちゃって遅すぎて困ります.
    以前、安さ(85円)につられてSTM32L010を使ったときにDelayの長さに困った記憶がよみがえりました。
    TIM21を1MHzに設定して、下記のコードで1us単位のDelayができるようにしてしのぎました(オーバーヘッド分Delayは長くなりますが……)。

    #include "stm32l0xx_hal.h"
    extern TIM_HandleTypeDef htim21;
    void delay_us(unsigned short duration)
    {
    htim21.Instance->CNT = 0;
    HAL_TIM_Base_Start(&htim21);
    while(htim21.Instance->CNT < duration) {}
    HAL_TIM_Base_Stop(&htim21);
    return;
    }

    返信削除
    返信
    1. Lですか、新しいめのラインナップでしたかなと
      なるほど、TIMと直接取引するプラン
      ハードウエアっぽくて、いいね!

      削除