STM32CubeMXを利用したHALドライバによるI2C EEPROM制御コードの記録です。
ターゲットマイコン:STM32L152RE
一部結果の入出力関数、遅延関数については割愛しております。
細かい説明抜きにソースコード貼り付けいたします。
【注意事項】
本記事中のソフトウェアはサンプルコードであり、ソフトウェアを使用した結果いかなる損害等が発生しても当方は一切責任を負いません。
●ソースコード
i2c_eep.c
/****************************************************************************
* I2C EEPROM (24LC512 or 24LC1025) 制御プログラム
*--------------------------------------------------------------------------*
* File i2c_eep.c
* Date 2020.01
* Rev 00.01
* Edit goroja
*
****************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "main.h"
#include "stm32l1xx.h"
#include "stm32l1xx_hal.h"
#include "i2c_eep.h"
#include "_lib.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
//#define DBG_I2C_EEP // I2C EEPROM制御プログラムデバッグ機能有効 (外部定義可)
#define EEP_SLAVE_ADDRESS 0xA0
#define EEP_BLOCK0 0x00
#define EEP_BLOCK1 0x08
#define I2C_SLAVE_ADDRESS7 0x00
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Gowbal variables ----------------------------------------------------------*/
extern I2C_HandleTypeDef hi2c1;
#define hI2C &hi2c1 // I2Cハンドル定義
HAL_StatusTypeDef i2c_result; // I2Cドライバ最終実行結果
/********************************************************
* 初期化
* in:
* なし
* out:
* EEP_OK 正常終了
********************************************************/
int eep_ini(void)
{
if (stf_I2C1_Init) return EEP_OK; // 初期化済み
// 自動生成コードにて初期化されるので本関数ではなにも行わない。
stf_I2C1_Init = 1; // I2C1初期化フラグセット
return EEP_OK;
}
/********************************************************
* データ読み込み (1byte)
* in:
* adr メモリアドレス (0x00000~0x1FFFF)
* rdp データ格納ポインタ
* len 読み込み数
* out:
* EEP_OK 正常終了
* EEP_ERR_RD リードエラー
********************************************************/
int eep_read(uint32_t adr, uint8_t* rdp, uint32_t len)
{
uint16_t CtrlByte;
if (!stf_I2C1_Init) return EEP_NO_INIT; // 未初期化
if (eep_rdy() != EEP_OK) return EEP_BUSY; /* バスビジー */
CtrlByte = (adr & 0x10000)?
EEP_SLAVE_ADDRESS | EEP_BLOCK1: // Block-1 select
EEP_SLAVE_ADDRESS | EEP_BLOCK0; // Block-0 select
// Ready待ち
for (int i=0; i<500; i++) {
i2c_result = HAL_I2C_IsDeviceReady(hI2C, CtrlByte, 1, 100); // レディー待ち
if (i2c_result == HAL_OK) break;
dly_tsk(1/MSEC);
}
if (i2c_result != HAL_OK) {
return EEP_BUSY; // ビジー
}
// Read
i2c_result = HAL_I2C_Mem_Read(hI2C, CtrlByte, (uint16_t)(adr&0xFFFF), sizeof(uint16_t), rdp, (uint16_t)len, 100);
if (i2c_result != HAL_OK) {
return EEP_ERR_RD;
}
return EEP_OK;
}
/********************************************************
* データ書き込み (1byte)
* in:
* adr メモリアドレス (0x00000~0x1FFFF)
* wdp 書き込みデータポインタ
* len 書き込み数
* out:
*
********************************************************/
int eep_write(uint32_t adr, uint8_t* wdp, uint32_t len)
{
uint16_t CtrlByte;
if (!stf_I2C1_Init) return EEP_NO_INIT; // 未初期化
if (eep_rdy() != EEP_OK) return EEP_BUSY; /* バスビジー */
CtrlByte = (adr & 0x10000)?
EEP_SLAVE_ADDRESS | EEP_BLOCK1: // Block-1 select
EEP_SLAVE_ADDRESS | EEP_BLOCK0; // Block-0 select
// Ready待ち
for (int i=0; i<500; i++) {
i2c_result = HAL_I2C_IsDeviceReady(hI2C, CtrlByte, 1, 100); // レディー待ち
if (i2c_result == HAL_OK) break;
dly_tsk(1/MSEC);
}
if (i2c_result != HAL_OK) {
return EEP_BUSY; // ビジー
}
// 書き込み
i2c_result = HAL_I2C_Mem_Write(hI2C, CtrlByte, (uint16_t)(adr&0xFFFF), sizeof(uint16_t), wdp, (uint16_t)len, 100);
if (i2c_result != HAL_OK) {
return EEP_ERR_RD;
}
return EEP_OK;
}
/********************************************************
* レディーチェック
* in:
* なし
* out:
* EEP_OK 正常終了
* EEP_BUSY ビジー
********************************************************/
int eep_rdy(void)
{
__IO uint32_t Timeout = 1000;
/* While the bus is busy */
while (__HAL_I2C_GET_FLAG(hI2C, I2C_FLAG_BUSY) != RESET) {
if((Timeout--) == 0) {
i2c_result = HAL_BUSY;
return EEP_BUSY;
}
dly_tsk(1/MSEC);
}
return EEP_OK;
}
#ifdef DBG_I2C_EEP
/********************************************************
* データダンプ
* in:
* adr メモリアドレス
* len ダンプ数
* mod 表示モード (0:Dump 1:LF)
* out:
* EEP_OK 正常終了
* EEP_ERR_RD リードエラー
* EEP_ADR_OVR アドレス範囲超過
********************************************************/
int eep_dump(uint32_t ba, uint32_t len, int mod)
{
static uint32_t adr = 0L;
static uint32_t wod = 256L;
int i, j, rsl;
uint32_t end;
uint8_t buf[16];
if (ba<=0x000FFFFF) adr = ba; /* set address */
if (len) wod = len; /* set length */
if (mod==0) {
/* ダンプ表示 */
_printf("address : ");
for (i=0,j=adr%16; i<16; i++,j++) _printf("+%01X ", j%16);
_crlf();
for (i=0,end=adr+wod; adr < end; i=(i+1)%16) {
if (i==0) _printf("%08lX: ", adr);
rsl = eep_read(adr, &buf[i], 1);
if (rsl != EEP_OK) {
// エラー
_printf("\r\n dump error. %d\r\n", rsl);
return rsl;
}
_printf("%02x ", (int)buf[i]);
if (i==15) {
_printf(" ");
for (j=0; j<16; j++) { /* 文字イメージ表示 */
// _printf("%c", (isprint(buf[j]))? (int)buf[j]: '.');
_printf("%c", (0x20<=buf[j] && buf[j]<=0x7E)? (int)buf[j]: '.' ); //←ARM系コンパイラ & Tera Termで表示こけ対策版
}
_crlf();
}
adr++;
if (adr>0x000FFFFF) break;
if (_stat()) { if (_getc() == 0x1B) break; } // 中断判定
}
i%=16;
if (i!=0) {
/* 残表示 */
for (j=16-i; j!=0; j--) _printf(" ");
_printf(" ");
for (j=0; j<i; j++) { /* 文字イメージ表示 */
// _printf("%c", (isprint(buf[j]))? (int)buf[j]: '.');
_printf("%c", (0x20<=buf[j] && buf[j]<=0x7E)? (int)buf[j]: '.' ); //←ARM系コンパイラ & Tera Termで表示こけ対策版
}
_crlf();
}
}
else {
/* 改行表示 */
for (end=adr+wod; adr < end; ) {
rsl = eep_read(adr, buf, 1);
if (rsl == EEP_OK) {
_printf( "%08lX,%02x\r\n", adr, (unsigned int)buf[0]);
} else {
// リードエラー
_printf("\r\n dump error. %d\r\n", rsl);
return rsl;
}
adr++;
if (adr>0x000FFFFF) break;
if (_stat()) { if (_getc() == 0x1B) break; } // 中断判定
}
}
if (adr>0x000FFFFF) {
adr = 0L;
return EEP_ADR_OVR;
}
return EEP_OK;
}
/*****************************************************************************
* SERIAL FLASH MEMORY DEBUG FUNCTION
*****************************************************************************/
int i2c_eep_main(int argc, char *argv[])
{
char *cmd;
cmd = argv[1];
strtolower(cmd); /* 小文字へ */
if (!strcmp(cmd, "init")) {
// フラッシュメモリ制御の初期化
int rsl;
stf_I2C1_Init = 0; // 初期化済みフラグクリア
rsl = eep_ini();
_printf(" done. (rsl:%d)\r\n", rsl);
}
else if (!strcmp(cmd, "read") || !strcmp(cmd, "r")) {
// シリアルフラッシュREADテスト
int rsl;
UB dt;
UW adr = 0L;
if (argv[2]) adr = strtoul(argv[2], NULL, 16);
rsl = eep_read(adr, &dt, 1);
_printf(" READ [%08X] -> %02X (r:%d)\r\n", adr, dt, rsl);
}
else if (!strcmp(cmd, "write") || !strcmp(cmd, "w")) {
// シリアルフラッシュWRITEテスト
int rsl;
UB dt = 0;
UW adr = 0L;
if (argv[2]) {
adr = strtoul(argv[2], NULL, 16);
if (argv[3]) {
dt = (UB)axtoi(argv[3]);
}
}
rsl = eep_write(adr, &dt, 1);
_printf(" WRITE [%08X] <- %02X (r:%d)\r\n", adr, dt, rsl);
}
else if (!strcmp(cmd, "dump") || !strcmp(cmd, "d")) {
// シリアルフラッシュ メモリダンプ
UW adr = 0L;
uint32_t wod = 0L;
int mod = 0;
int rsl, c;
if (argv[2]) adr = strtoul(argv[2], NULL, 16);
if (argv[3]) wod = strtoul(argv[3], NULL, 16);
if (argv[4]) mod = atoi(argv[4]);
do {
rsl = eep_dump(adr, wod, mod);
if (rsl != EEP_OK) break; // 終了
if (wod != 0L) break; // 終了
adr = (UW)(-1L);
while (!_stat()) dly_tsk(10L/MSEC); // キー入力まで待つ
c = _getc();
if (c == CHR_ESC) {
_printf("\r\n stop\r\n");
break; // 終了
}
} while (1);
_puts(" done.");
}
else if (!strcmp(cmd, "rsl") || !strcmp(cmd, "result")) {
// 最終実行結果表示
_printf(" HAL Last result = %02XU\r\n", i2c_result);
}
else {
_puts(" Illegal command.");
}
return 0;
}
#endif //DBG_I2C_EEP
/*** End of file ***/
●ヘッダファイル
i2c_eep.h
/**
******************************************************************************
* @file i2c_eep.h
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __I2C_EEP_H
#define __I2C_EEP_H
#ifdef __cplusplus
extern "C" {
#endif
#include "main.h"
#include "stm32l1xx.h"
#if defined(EEP_24LC512)
#define EEP_MAX_SIZE (64*1024) // 64KB
#elif defined(EEP_24LC1025)
#define EEP_MAX_SIZE (128*1024) // 128KB
#else
#warning ※EEPROM型番を定義する。(容量は初期値 4096kB)
#define EEP_MAX_SIZE (4096) // 4KB
#endif
/*** エラーコード定義 ***/
#define EEP_OK (0) // 正常終了
#define EEP_BUSY (-1) // デバイスビジー
#define EEP_ERR_RD (-2) // リードエラー
#define EEP_ERR_WR (-3) // ライトエラー
#define EEP_ADR_OVR (-4) // アドレス範囲超過
#define EEP_ERR_BER (-5) // ブロック消去エラー
#define EEP_ERR_CER (-6) // チップ消去エラー
#define EEP_ERR_PRM (-7) // パラメータエラー
#define EEP_ERR_INTER (-9) // 内部エラー
#define EEP_TMO1 (-11) // 処理タイムアウト
#define EEP_TMO2 (-12) // 処理タイムアウト
#define EEP_TMO3 (-13) // 処理タイムアウト
#define EEP_TMO4 (-14) // 処理タイムアウト
#define EEP_TMO5 (-15) // 処理タイムアウト
#define EEP_TMO6 (-16) // 処理タイムアウト
#define EEP_TMO7 (-17) // 処理タイムアウト
#define EEP_TMO8 (-18) // 処理タイムアウト
#define EEP_TMO9 (-19) // 処理タイムアウト
#define EEP_NO_INIT (-20) // 未初期化エラー
#define EEP_INV_CALL (-21) // 無効関数呼び出し
/*** 関数プロトタイプ定義 ***/
int eep_ini(void);
int eep_wen(void);
int eep_read(uint32_t ba, uint8_t* rdp, uint32_t len);
int eep_write(uint32_t ba, uint8_t* wdp, uint32_t len);
int eep_rdy(void);
int eep_poll(uint8_t CtrlByte);
int eep_ber(uint32_t ba, int bs, int dt);
int eep_cer(void);
int eep_dump(uint32_t ba, uint32_t len, int mod);
#ifdef __cplusplus
}
#endif
#endif /* __I2C_EEP_H */
/****END OF FILE****/
以上