STM32H7を使ってみる2 -スライムが強すぎてアリアハンから出られない件-

おおねむいよしんでしまうとはなさけないっ…ていうかさ、お前このぶろぐ立ち上げて
10年間ずっと何やってきたんだ?毎年初心に帰ってないでさっさと先に進めや!!1!と
王様に副業先とほぼ同じ内容(本業は虹裏メイド)で怒られてる今現在でございますが
STM32って言う名前のスライムなんですがこれ世間一般の認識の青色のプルプル形状してて
ワンパンで死ぬ雑魚
と違ってねむいさんの前に立ちはだかるそいつは液状で高速で
動き、物理攻撃が効かず強力な"溶かす"攻撃してくる最強クラスの敵なんですがねむい
さんのほうがワンパンで死んでしまうのですがこいつのせいでFatFsの実装という最初期
段階で踏みとどまって10年が経過してしまったのですが年数の経過とともにねむいさん
倒しまくって経験値増やしていった結果スライム君の方が先にレベルアップしてしまって
STM32F4とかF7とかどんどん数字が上がって挙句の果てにクロック周波数480MHz
デュアルコアH7とかにパワーアップしてしまったスライムに包囲されアリアハンは壊滅
寸前もうだめだでもよく考えたらねむいさんの職業て勇者じゃなくて虹裏メイドだから
別に無理してアリアハンから出なくてもいいんじゃねっていう弱い考えが浮かびそうに
なりますが今度こそスライムを倒すために異世界モノなろう小説風に毎回恒例の初心
表明を宣言するのでした!10年後に転生したら10年たっていた件


さて、謎の文字列は置いといてSTM32H747I-Discovery向けいつものはこちらになります。
まだ暫定版なので明らかなバグ以外はご意見無用とさせていただきます!!!!

上記のブツを元にプログラムの解説をしていきますのでよろしくお願いします。

●アリアハン脱出作戦開始

まずすべきことはSTM32H7のメモリ/バスのアーキテクチャを理解してプログラム作りの
土台を作ること、つまりはH7向けのリンカスクリプトとビルド環境を構築することです。


STM32F7に比べてメモリ構成はさらに複雑になっています。しかもデュアルコアなので
それを意識してメモリを分け分けしないといけません。
ねむいさんの戦略としては当分の間はH7コアをシングルで動かすことを主眼に入れ、
上記画像のように組んでみました。H7コアと同じ周波数で動作できる密結合メモリの
DTCM-RAMはほぼスタック専用に、大容量&バス幅64bitのAXI-SRAMはDATA,BSS,HEAPに
割り振ります。ITCM-RAMも容量が増えたので今回から積極的に使用していきます!
そしてAHBバスマトリクスに配置されているSRAMですがこちらはバスマトリクスがどこで
繋がってるかをしっかりわかっておかないとDMAとかでハマるので以後個別に詳しく
解説しようと思います。

また、すでに先達の使用者からよく言われていることですがF7では便利だったDTCMは
H7に上がってDMAの制約が極めてきつくなり、実質上直接DMA不可となっていますF**K!!!!
一応やれないこともないのですがMasterDMAを介した面倒な間接転送となります。
これについてもいずれ別記事で詳しく解説します。


/* Linker script Upperside for STM32H747XIH6		*/
/* Nemui Trinomius (http://nemuisan.blog.bai.ne.jp) */

OUTPUT_FORMAT ("elf32-littlearm")

/* Memory Spaces Definitions */
MEMORY
{
/* Instruction TCM SRAM */
ITCM_RAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64k
/* Data TCM SRAM */
DTCM_RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128k
/* AXI-SRAM D1 Domain */
AXI_SRAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512k
/* AHB-SRAM1 D2 Domain */
SRAM1_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 128k
/* AHB-SRAM2 D2 Domain */
SRAM2_D2 (xrw) : ORIGIN = 0x30020000, LENGTH = 128K
/* SRAM3 D2 Domain */
SRAM3_D2 (xrw) : ORIGIN = 0x30040000, LENGTH = 32k
/* SRAM4 D3 Domain */
SRAM4_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64k
/* Backup SRAM */
BKP_SRAM (rw) : ORIGIN = 0x38800000, LENGTH = 4k
/* External SDRAM(FMC) */
EXT_SDRAM (xrw) : ORIGIN = 0xD0000000, LENGTH = 32M
/* Main Embedded Dual-Bank FlashROM */
FLASH_ROM (rx) : ORIGIN = 0x08000000, LENGTH = 2M
/* External Dual-Mode QSPI-ROM */
QSPI_ROM (rx) : ORIGIN = 0x90000000, LENGTH = 128M
}

/* higher address of the stack bottom,AAPCS said "stack MUST BE 8byte alignment". */
_estack = (ORIGIN(DTCM_RAM)+LENGTH(DTCM_RAM)) & ~ 0x7;

/* higher address of the heap end */
_eheap = ORIGIN(AXI_SRAM)+LENGTH(AXI_SRAM);


/* include the section management sub-script */
INCLUDE "STM32H7xxxx_FLASH.ld"


こんな感じでリンカスクリプトに落としました。
今回はスクリプトそのものも見直して意味不明なことやってた記述は排除/修正
しております!その修正内容は…


ねむいさんスタックポインタとかヒープの設定で9年間くらい謎の引き算やってた…
なんでこんなんでアライメントが揃うと思っていたのか…
(↑ARM7TDMIは設定するSRAMの最終アドレスから-8バイト引いた値をspに設定しないと
  いけなかったのでCortex-Mからスタック設定の仕様が変わった後も仕様をよく見
  ないでやっていたと考えられる…これじゃスライムにやられるわけだ)


●クロック設定とかGPIO入出力とか
こちらに関してはSTM32H7CubeのBSPを参考にすれば問題はありません。
最大480MHzで動作するH7コアですがエラッタやSDRAMを使った時の速度的な制約があり
H7コアクロック400MHz、AXI/AHBバスクロック200MHzがつぶしが効く設定となり、BSP
のExampleではすべてこのクロック周波数設定となっています。
これをそっくりそのまま頂いちゃいましょう!
ぇ…?CubeMX?なんスかそのバグコード生成機
/* Defines -------------------------------------------------------------------*/
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 400000000 (Cortex-M7 CPU Clock,upto 480MHz)
* HCLK(Hz) = 200000000 (Cortex-M4 CPU, Bus matrix Clocks,upto 200MHz)
* AHB Prescaler = 2 (AHB/AXI Bus Matrix Clock upto 200MHz)
* D1 APB3 Prescaler = 2 (APB3 Clock upto 100MHz)
* D2 APB1 Prescaler = 2 (APB1 Clock upto 100MHz)
* D2 APB2 Prescaler = 2 (APB2 Clock upto 100MHz)
* D3 APB4 Prescaler = 2 (APB4 Clock upto 100MHz)
* HSE Frequency(Hz) = 25000000
* VCO Frequency = 800000000 (160*5)
* PLL_M = 5
* PLL_N = 160
* PLL_P = 2
* PLL_Q = 4
* PLL_R = 2
* VDD(V) = 3.3
* Flash Latency(WS) = 4
* @param None
* @retval None
*/
#define PLL1_M 5
#define PLL1_N 160
#define PLL1_P 2
#define PLL1_Q 4
#define PLL1_R 2
#define PLL1_FRACN 0
上記はコア/バス/ペリフェラルクロック用のPLL設定値のdefineです。
F7と比べるとPLLが増えてかなり変わってる感じがしますね。
hw_config.cに具体的なコードがあるのでご参考に。
また、ユーザーマニュアルではカーネルクロックなるややこしい概念が出てきますが
殆どのペリフェラルではHCLK(AHB)のクロックを指します。

static void LED_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIO_LED clock */
GPIO_LED_CLKEN();

/* Configure GPIO for LEDs as Output push-pull */
GPIO_InitStructure.Pin = LED_D1;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = 0;
HAL_GPIO_Init(GPIO_LED1, &GPIO_InitStructure);
LED_D1_OFF();

GPIO_InitStructure.Pin = LED_D2;
HAL_GPIO_Init(GPIO_LED2, &GPIO_InitStructure);
LED_D2_OFF();
GPIO_InitStructure.Pin = LED_D3;
HAL_GPIO_Init(GPIO_LED3, &GPIO_InitStructure);
LED_D3_OFF();
GPIO_InitStructure.Pin = LED_D4;
HAL_GPIO_Init(GPIO_LED4, &GPIO_InitStructure);
LED_D4_OFF();
}

LED(GPIO)の出力設定はF7とほぼ変わりませんが100MHz越えのI/Oトグリング対応の為
"GPIO_SPEED_FREQ_VERY_HIGH"という定義が追加されてます。特に必要が無い場合は
VERYHIGHにしておきましょう。

static void KEY_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIO_LED clock */
RCC->AHB4ENR |= (RCC_AHBPeriph_GPIO_KEY_USER1);
RCC->AHB4ENR |= (RCC_AHBPeriph_GPIO_KEY_SEL);
RCC->AHB4ENR |= (RCC_AHBPeriph_GPIO_KEY_DOWN);
RCC->AHB4ENR |= (RCC_AHBPeriph_GPIO_KEY_LEFT);
RCC->AHB4ENR |= (RCC_AHBPeriph_GPIO_KEY_RIGHT);
RCC->AHB4ENR |= (RCC_AHBPeriph_GPIO_KEY_UP);

/* Configure GPIO for Key Input */
GPIO_InitStructure.Pin = KEY_USER1;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;;
GPIO_InitStructure.Alternate = 0;
HAL_GPIO_Init(GPIO_KEY_USER1, &GPIO_InitStructure);

GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Pin = KEY_SEL_PIN;
HAL_GPIO_Init(GPIO_KEY_SEL, &GPIO_InitStructure);
GPIO_InitStructure.Pin = KEY_DOWN_PIN;
HAL_GPIO_Init(GPIO_KEY_DOWN, &GPIO_InitStructure);
GPIO_InitStructure.Pin = KEY_LEFT_PIN;
HAL_GPIO_Init(GPIO_KEY_LEFT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = KEY_RIGHT_PIN;
HAL_GPIO_Init(GPIO_KEY_RIGHT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = KEY_UP_PIN;
HAL_GPIO_Init(GPIO_KEY_UP, &GPIO_InitStructure);
}

入力についても同様です。
H7-Discvoeryは4+1入力ジョイスティックが追加されたので物理キー入力処理も追加
しております
/* Macros */
/* uncomment to enable joy input */
//#define USE_HWKEY_INPUT_SUPPORT

/* ITCM Fastest call for IRQ */
#define __ITCM __attribute__ ((section (".itcm")))
//#define __ITCM __attribute__ ((long_call, section (".itcm")))

hw_config.h内で上記の物理キー入力有効無効が切り替えられるようにしておきました。
タッチパネルがあるのでデフォルトは無効です。


●タイムベースは重要ですよね
	/* Making MilliSecond-Order Timer */
/* Select Clock Source */
SystemCoreClockUpdate();
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* Setup SysTick Timer for 1 msec interrupts */
if (SysTick_Config(SystemCoreClock/interval))
{
/* Capture error */
while (1);
}

マイコンを動かすにおいて必要不可欠なタイマですがsystickの設定についてはF7と
殆どかわりません。ほんの少しの修正で使用可能です。
ねむいさんのいつものではミリ秒オーダーのタイムベースとして動作させてます。

	/* Making MicroSecond-Order Timer uses general purpose timer! */
/* Enable timer clock */
USEC_TIMx_CLKEN();

/* calculate TIMx(2~5) Prescaler clock(D2 Domain) */
if(RCC->D2CFGR & RCC_D2CFGR_D2PPRE1){
if((RCC->D2CFGR & RCC_D2CFGR_D2PPRE1) == RCC_D2CFGR_D2PPRE1_DIV2){
cal_usec_divide = SystemCoreClock/2; /* (HCLK(=SYSCLK/2)*2)*2 */
}
else if((RCC->D2CFGR & RCC_D2CFGR_D2PPRE1) == RCC_D2CFGR_D2PPRE1_DIV4){
cal_usec_divide = SystemCoreClock/4; /* (HCLK(=SYSCLK/2)*4)*2 */
}
else if((RCC->D2CFGR & RCC_D2CFGR_D2PPRE1) == RCC_D2CFGR_D2PPRE1_DIV8){
cal_usec_divide = SystemCoreClock/8; /* (HCLK(=SYSCLK/2)*8)*2 */
}
else if((RCC->D2CFGR & RCC_D2CFGR_D2PPRE1) == RCC_D2CFGR_D2PPRE1_DIV16){
cal_usec_divide = SystemCoreClock/16; /* (HCLK(=SYSCLK/2)*16)*2 */
}
}

TimHandle.Instance = USEC_TIMx;
TimHandle.Init.Period = UINT32_MAX;
TimHandle.Init.Prescaler = ((cal_usec_divide)/USEC_INTERVAL) - 1;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
{
/* Capture error */
while (1);
}

USEC_TIMx->CR1 &= ~(TIM_CR1_UIFREMAP); /* Disable UIF Remap(Must Need!) */

HAL_TIM_Base_Start(&TimHandle);

μ秒オーダーは32bitタイマを利用しています。F7/H7でTIM5のフリーランニング動作で
実現しております。ただH7ではAHBの番号が異なっているので変更は必用です。
また、バスクロックも2倍に上がっているのでそれを考慮した計算値を与えましょう。
各詳細はsystick.c参照

●リングバッファ付UARTもはや基本
ねむいさんUARTという文字列をなぜかずっとウラートと呼んでました…ソビエト連邦かな
(正解:ユーアート)

#if defined(USE_STM32H747I_DISCO)
#define UART_DEFAULT_NUM 1
#define UARTx USART1
#define USARTx_IRQHandler USART1_IRQHandler
#define USARTx_CLKEN() ¥
/* Enable GPIO clock(UART_TX) */ ¥
RCC->AHB4ENR |= (RCC_AHB4ENR_GPIOAEN); ¥
/* Enable GPIO clock(UART_RX) */ ¥
RCC->AHB4ENR |= (RCC_AHB4ENR_GPIOAEN); ¥
/* Enable UART clock */ ¥
RCC->APB2ENR |= (RCC_APB2ENR_USART1EN);
#define USART_TxPin GPIO_PIN_9
#define USART_RxPin GPIO_PIN_10
#define USART_TxPort GPIOA
#define USART_RxPort GPIOA
#define USART_TXALT GPIO_AF7_USART1
#define USART_RXALT GPIO_AF7_USART1

/* This is the ARDUINO Option(not used) */
//#define UART_DEFAULT_NUM 8
//#define UARTx USART8
//#define USARTx_IRQHandler USART8_IRQHandler

#else
#error "Select or make board settings!!"
#endif

こちらについてもF7と大きな変更はなく、H7-Discovery内のSTLink/V3のVCPにつなが
っているPA9(TX),PA10(RX)を割り当てるだけです。まぁこのポートはブートローダー
でも使うSTM32伝統のUARTポートみたいな感じですね〜

#if defined(UART_INTERRUPT_MODE)
/**************************************************************************/
/*!
@brief Handles UARTx global interrupt request.
@param None.
@retval None.
*/
/**************************************************************************/
__ITCM void USARTx_IRQHandler(void)
{
uint32_t IntStat = UARTx->ISR;

if(IntStat & USART_ISR_RXNE_RXFNE)
{
/* Clear Errors */
UARTx->ICR = USART_ICR_ORECF | USART_ICR_NECF | USART_ICR_FECF | USART_ICR_PECF;

/* Advance buffer head. */
unsigned int tempRX_Head = ((&USARTx_Buf)->RX_Head + 1) & (UART_BUFSIZE-1);

/* Check for overflow. */
unsigned int tempRX_Tail = (&USARTx_Buf)->RX_Tail;
uint8_t data = UARTx->RDR;

if (tempRX_Head == tempRX_Tail) {
/* Overflow MAX size Situation */
/* Disable the UART Receive interrupt */
UARTx->CR1 &= ~(USART_CR1_RXNEIE);
}else{
(&USARTx_Buf)->RX[(&USARTx_Buf)->RX_Head] = data;
(&USARTx_Buf)->RX_Head = tempRX_Head;
}
}

if(IntStat & USART_ISR_TXE_TXFNF)
{
/* Check if all data is transmitted. */
unsigned int tempTX_Tail = (&USARTx_Buf)->TX_Tail;
if ((&USARTx_Buf)->TX_Head == tempTX_Tail){
/* Overflow MAX size Situation */
/* Disable the UART Transmit interrupt */
UARTx->CR1 &= ~(USART_CR1_TXEIE);
}else{
/* Start transmitting. */
uint8_t data = (&USARTx_Buf)->TX[(&USARTx_Buf)->TX_Tail];
UARTx->TDR = data;

/* Advance buffer tail. */
(&USARTx_Buf)->TX_Tail = ((&USARTx_Buf)->TX_Tail + 1) & (UART_BUFSIZE-1);
}
}
}
#endif

また、実際の通信では割り込みを用いてノンブロッキング(非同期)のリングバッファ
構成を取っています。割り込みルーチン本体はITCMにコードを配置して超高速に処理
できるようにしておきました。

/**************************************************************************/
/*!
@brief Copy Time-Critical codes into ITCM-RAM.
@param None.
@retval None.
*/
/**************************************************************************/
static void datacopy(unsigned int romstart, unsigned int start, unsigned int len)
{
unsigned int *pulDest = (unsigned int*) start;
unsigned int *pulSrc = (unsigned int*) romstart;
unsigned int loop;
for (loop = 0; loop < len; loop = loop + 4)
*pulDest++ = *pulSrc++;
}
/* _stitcm,_sitcm,_eitcm are MUST be decrare in likerscript file */
static void ITCM_Datainit(void)
{
unsigned int *LoadAddr, *ExeAddr, *EndAddr, SectionLen;

/* Copy ITCM Codes into ITCM-RAM */
LoadAddr = &_stitcm;
ExeAddr = &_sitcm;
EndAddr = &_eitcm;
SectionLen = (void*)EndAddr - (void*)ExeAddr;
datacopy((unsigned int)LoadAddr, (unsigned int)ExeAddr, SectionLen);
}

当たり前の事ですがITCMで動作させるためにはあらかじめコードを転送しておかないと
いけないので起動直後とかにコードを送っておきましょう。
その他細かい部分はhw_config.cに詰まっていますのでそちらをご参照ねがいます。





というわけでまだほんの少ししか紹介出来ておりませんがひとまずH7を動かすための
基本的な項目の解説を行いました。次回からはH7最大の難関であるキャッシュとDMAの
問題に切り込んでいこうと思います!

STM32H7はぢめました・・・本当にいまさら


キタ━━━(゚∀゚)━━━!!
まってたぜぇ…この瞬間(とき)をよぉ…!

出る出る詐欺で一向に出る気配がなかったSTM32HのDiscoveryがついに私の
手元に入りました…!本当に長かった…!(※正式名称はSTM32H747I-DISCO)



基板の形状はSTM32F769I-Discoveryとほぼ同一ですね


メインCPUはH7シリーズ第二世代のSTM32H747XIH6です。第2世代になって何が
変わったかというとなんとCortex-M4コアがもう一つ付いたデュアルコア構成と
なっております!!!!


そんでもってビルトインされたSTLinkも最新のV3仕様で使用CPUはSTM32F723です!
なんとオンチップでUSB-Highspeedの物理層が乗っかっているすごい奴なのです!!


SDRAMはISSI製の32Bitデータバスの32MByteの奴が乗っかっています。


液晶を外して基板表面も見てみましょう。液晶モジュールはSTM32F769I-Discoveryと
全く同じMIPI-DSI接続のWVGAなTFT-LCDです(容量性タッチパネルICも同じ)


LANの物理層はおなじみMicrochipのLAN8742Aです。


そしてこの多CHフォトカプラみたいなのなに…と思ったのですがこれがQSPI-ROM
なのです!マイクロンのMT25QL512ABB8ESF-0SITが乗っています。


そして基板の反対側にもついている。STM32H747XIでは2つのQSPI-ROMを一つの大
容量クアッドSPI-ROMのように使えるDUAL-QUAD Modeが搭載されております!


I2S-CodecはおなじみのWM8994Eです。


そしてArduinoスタイルのコネクタの他にもI/Oを外部に拡張できるコネクタが
新設されました!Xbeeとかをそのままつけられそうですね〜



ぜんぜんピン間隔ちがってたorz


外観はこの辺にしておいてUSBMicroケーブルぶっ刺して通電です!
STMicroがイチオシするSTemWinとTouchGFXをふんだんに使用したでもアプリが
起動します。


TouchGFXはSTM32F769I-Discoveryの時のようにCPUの負荷状態とか見られる機能や
JPEGやDMA2Dみたいな各種ハードウエアアクセラレーションの効果を見ることが
できるプログラムもあり…おや…これは…


ク ソ ゲ ー 再 び
モーやってられませんわこれ(←律儀にやる人


さて、STM32H7でもいつものベアメタルでとりあえず組んでみる予定です。
現在はLチカにはぢまってねむいさんのコンテンツでは欠かせないDMA動作を絡めた
FatFsの実装まで完了しております(画像はLED点滅しているところ)。

H7に上がって機能も制約もF7とは段違いに変わってますので実装を進めながら
次回以降にみっちりと解説していけたらと思います!

いろいろ試す38

今超くそ忙しくなってます…が、僅かな隙間を見つけて記事を更新し続けて行こうと
思います…!!!!


●ビルド・デバッグ環境構築をWin10対応に
昨年末に来年度からがむばりますと言いましたがようやく手を付けました…!
ARMマイコンのねむいさん流ビルド環境構築手順OpenOCDを使ったデバッグ
手順
のWindows10対応版です!

と言ってもXPでやってた頃とほとんど変わってませんけどね〜
皆様に「説明の意味がわからない」と評判だったねむいさん特有の言い回しとかは
まだ随所に残っていますが文章も見直してなるべくシンプルにするべく更新を続けて
いこうと思います…!

…ぇ?やっと10対応にしたのにWindows10の次のOS開発中ってマジですか…!?


●ARM-GCCの新しいのが出た
昨年末にARM-GCCが更新したばかりですがarm-none-eabi-objcopyがバグってihexが
出力できないという致命的な不具合を抱えていたのですがそれが修正されてリリース
となりました。本来なら1年くらいスルーされてるはずなのですが問題が大きくなり
すぎてGCC本家のアップデートに合わせてリリースされたようです。

今回のarm-none-eabi-objcopyはバグってエラー吐かずちゃんとihexが出力されます
ので皆さまも安心してお使いください。


●Windows10のクイックアクセスが憎いよう!!!!

なんでや…ドラッグアンドドロップで左ペインのディレクトリにファイルが
移動できない…orz

調べたら鬱陶しいクイックアクセスをレジストリ編集して消滅させたらこうなる
そうです…F*************CK!!!


●STM32H7Discoveryようやく市中に
待ってた…1年半くらい…
正確には「STM32H747I-Disco」ですがようやくmouserとかで買えるようになってますね〜
さっそくねむいさんも注文してみます!!!
来月位にH7の記事書けたらいいな〜と思います☆

3D-TLC搭載のマイクロン製産業用MicroSDを使ってみる

とある用事で大阪に降りた際に寄ったいつものPCショップでねむいさんが前から目を
付けていたMicron製のMicroSD(ややこしい)を発見し、早速入手しました!


諸般の事情で128GB‥かつてはこの容量だと10000円越えだったのに産業用でも
5000円以下となりずいぶんと安くなったものです…



正式な型番はMTSD128AHC6MS-1WTとなっております。
Micron公式では産業用向けとして紹介されており3D-TLCセルを使用した大容量・長寿命
を以てネットワーク監視カメラ用途を想定したものとなってりますが当然のことながら
ドラレコにも最適です☆
そして産業用ならでわのS.M.A.R.T.(以下SMART)も当たり前のように存在しており、
ねむいさんはもちろんそちらの方が目当てだったりしてました!


-----------------------------------------------------------------------
CrystalDiskMark 5.2.1 x64 (C) 2007-2017 hiyohiyo
Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]
* KB = 1000 bytes, KiB = 1024 bytes

Sequential Read (Q= 32,T= 1) : 70.235 MB/s
Sequential Write (Q= 32,T= 1) : 45.021 MB/s
Random Read 4KiB (Q= 32,T= 1) : 4.693 MB/s [ 1145.8 IOPS]
Random Write 4KiB (Q= 32,T= 1) : 4.378 MB/s [ 1068.8 IOPS]
Sequential Read (T= 1) : 71.302 MB/s
Sequential Write (T= 1) : 42.824 MB/s
Random Read 4KiB (Q= 1,T= 1) : 3.534 MB/s [ 862.8 IOPS]
Random Write 4KiB (Q= 1,T= 1) : 3.475 MB/s [ 848.4 IOPS]

Test : 1024 MiB [H: 0.0% (0.0/116.1 GiB)] (x5) [Interval=5 sec]
Date : 2019/06/07 21:17:20
OS : Windows 7 Professional SP1 [6.1 Build 7601] (x64)
Micron Industrial MicroSDXC 3D-TLC UHS-1 MTSD128AHC6MS-1WT ADR-3ML35BK USB3.0 uPF720202 M570RU
まずはPC上でベンチマークをとってみました
Sandiskの産業用(第三世代)と比べてみますとチマチマ書き込みがかなり強い印象がありますね(理由は後述)。

FatFs module test terminal for STM32F769NIH6
LFN Enabled, Code page: 932
AppVersion : W.I.P
Build Date : Jun 8 2019
>fg piano
rc=0 FR_OK
>fo 1 ftbt.mp3
rc=0 FR_OK
>fr 132949600
132949600 bytes read with 18452 kB/sec.
>fs
FAT type = exFAT
Bytes/Cluster = 131072
Number of FATs = 1
Root DIR entries = 17931
Sectors/FAT = 16384
Number of clusters = 951296
Volume start (lba) = 32768
FAT start (lba) = 49152
DIR start (lba,clustor) = 4
Data start (lba) = 65536

Volume name is MTSD128AHC
Volume S/N is DAD2-8E1E
...
1 files, 132949600 bytes.
0 folders.
121765888 KiB total disk space.
121635456 KiB available.
>ds 0
rc=0
Drive size: 243597312 sectors
Erase block size: 8192 sectors
Default r/w block size: 512 bytes
Card type: SDv2(Block)
CSD:
00000000 40 0E 00 32 5B 59 00 03 A1 3F 7F 80 0A 40 00 0F @..2[Y...?...@..
CID:
00000000 09 41 50 4D 42 35 33 41 01 E1 00 6F 10 01 28 C5 .APMB53A...o..(.

Parsing SD CID Register
Manufacturer ID :0x9
OEM/Application ID :AP
Product Name :MB53A
Product HwRev :0
Product SwRev :1
Serial Number :0xE1006F10
DateCode.Month :8
DateCode.Year :2018

OCR:
00000000 C1 FF 80 00 ....
SD Status:
00000000 80 00 00 00 08 00 00 00 04 00 90 00 01 33 19 00 .............3..
00000010 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
SCR:
00000000 02 45 80 43 01 00 00 00 .E.C....

Parsing SCR
SD Spec Version :2
SD Spec Version 3 :1
SD Spec Version 4 :0
SD Spec Version X :1
SD Security :4
SD Bus Width :5

SD_Spec V5.xx!
Detected as SDXC Card!
Available UHS-I Mode.
Available UHS Speed Class U1.
Available SD Speed Class 10.
Video Speed Class NOT Supported.
Available Application Performance Class1, A1 Card.
お次はねむいさんのいつものでカード情報を読み出してみました。
FatFs移植例も7月更新分からSDカードのサポート情報の細分化を進めており各種スピード
クラスのサポート状況が分かるようになりました。
このMicron製の奴はカード本体には記載はないのですがA1クラスサポートとなってお
ります。いちおう公式でもA1対応と言っておりますが製造時にロゴのレタリング追加
するの忘れちゃっただけなんでしょうけど。

そしてこのマイクロSD買ったメインの目的のSMART情報の取得です!
このカードではDelkinやSandiskと同じくCMD56でSMART情報の取得が可能なのですが、
なんと公式に資料を公開しており超太っ腹です!こちらの資料によるとCMD56の引数は
0x110005FBとなります。これを引数にしてCMD56を打ち込んでやると無事SMARTの
情報を取ることができました♥(もちろんSPI互換モードでも獲れます )
こちらに読みだした生データを置いておきますのでご参考に。




今回SMARTをとるにあたり上のテクニカルノート見て気づいたのですがこのMicron製の
奴はNANDメモリセルが3D-TLCなのですが一部はSLCのようなんですよね…
"Internalbuffer"としてどういう使い方するかによりますがFAT/exFATファイルシステムで
使用する際に先頭にある書き換えが激しいFAT領域まではSLCの区画を使用して比較的
消去サイクルが少ないデータ領域に関しては3D-TLCの区画が使用されている…
…といった感じなのでしょうか???
そしてSLCの区画をバッファとして使用することによってチマチマ書き込みも
強化されている感がしますね。

こういったハイブリッドなメモリセル構成にすることでコストパフォーマンスと信頼性を
同時に確保して大容量化を目指す路線が今後のSDカードで流行りそうですね〜
SDUCでの最大容量が128TBだそうですが近い将来にあっさり到達してしまいそうです。

Go to top of page