ハード構成について
執筆中
STマイコンのI2C通信での注意点
- コードジェネレーターでジェネレートを行うと、ソースコードが生成されますが、IDE側のバグ?でI2C通信の初期化設定が正しくないです。
stm32c0xx_hal_msp.c
void HAL_I2C_MspInit(){
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL; /*$ <-- ここが誤り $*/
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF6_I2C1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
I2C通信を行う際は、プルアップ抵抗が必ず必要なので、メンバー変数Pullの設定が誤っています。よって、以下のように設定し直してください。
stm32c0xx_hal_msp.c
void HAL_I2C_MspInit(){
GPIO_InitStruct.Pull = GPIO_PULLUP;
}
2. スレーブアドレス設定の注意点1。
まず、スレーブアドレスはコントロールレジスタの1ビット目~7ビット目までの7ビットで指定します。 その為、スレーブアドレスをスレーブ側のSTマイコンで設定する際には、設定するスレーブアドレスから1ビット左シフトした値を設定する必要があります。
例えば、スレーブアドレスが0x6F(111)の場合は、コーディング上では左に1ビットシフトした0xDE(222)を設定する必要があります。
main.c
MX_I2C1_Init(){
hi2c1.Init.OwnAddress1 = 0xDE;
}
3. I2C通信をする際は、エラー処理を忘れずに。
I2C通信を行うと、何かしらの原因で通信エラーとなる事があります(HAL関数の場合、戻り値がHAL_ERRORになる)。この時、通信の初期化処理を行わないと、通信エラーが永遠に続きます(原因は不明ですが、私の測定環境ですと20分ぐらい連続でI2C通信を行うとこの現象になります)。
ですので、以下のように通信エラーになった時の処理を設けておきましょう。
main.c
dummy_func()
ret_val = HAL_I2C_Master_Transmit();
if( ret_val == HAL_ERROR ){
I2C_RESET() ;
}
void I2C_RESET( void ){
HAL_I2C_DeInit(&hi2c1) ;
HAL_I2C_Init(&hi2c1) ;
}
ソースコード
マスタ側マイコンのmain.cの主な処理は以下の通り
main.c
int main(void){
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET) ;
/*$ I2Cマスター送信を行う $*/
ret_val = HAL_I2C_Master_Transmit(&hi2c1, slave_add, (uint8_t *)buf, 1, 3000);
/*$ マスター送信を正しく行えた場合 $*/
if( ret_val == HAL_OK ){
/*$ スレーブからデータを取得する $*/
ret_val = HAL_I2C_Master_Receive(&hi2c1, slave_add, (uint8_t *)buf, 1, 3000);
/*$ マスター受信を正しく取得出来た場合 $*/
if( ret_val == HAL_OK ){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET) ;
HAL_Delay(100) ;
} else {
I2C_RESET() ;
}
} else {
I2C_RESET() ;
}
/*$ 1byteを超えた場合 $*/
if( buf[0] >= 255 ){
buf[0] = 0 ;
}
}
}
スレーブ側マイコンのmain.cの主な処理は以下の通り
main.c
int main(void){
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/*$ LEDを点灯 $*/
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET) ;
/*$ I2C_スレーブ受信 $*/
ret_val = HAL_I2C_Slave_Receive(&hi2c1, (uint8_t *)buf, 1, 1000) ;
/*$ 受信が無事に成功出来た場合 $*/
if( ret_val == HAL_OK ){
/*$ 1だけインクリメントする $*/
buf[0] += 1 ;
/*$ buf[0]をスレーブ送信する $*/
ret_val = HAL_I2C_Slave_Transmit(&hi2c1, (uint8_t *)buf, 1, 1000) ;
/*$ スレーブ送信が成功した場合 $*/
if( ret_val == HAL_OK ){
/*$ 100msecだけLEDを消す $*/
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET) ;
HAL_Delay(100) ;
buf_record[index++] = buf[0] ;
if( index >= 1000 ){
index = 0 ;
}
} else {
I2C_RESET() ;
}
} else {
I2C_RESET() ;
}
}