STM32F103C8 กับ EEPROM_24LC01B_MCP ทาง I2C Gen_Code ด้วย CubeMX นิ่งเลย T_T!

Started by TaoTao, February 25, 2017, 10:09:10 AM

Previous topic - Next topic

TaoTao

อย่างอื่น ที่ลองๆ มา ของ เบอร์นี้ ก็ทำงานดีนะครับ
ที่ยังไม่ทำงาน ก็ I2C ของเบอร์นี้อ่ะครับ

HW เช็คหลายรอบมากแล้ว ไม่มีอะไรผิดนะครับ
ค่า R Pullup ตาม Datasheet เลย

และ ให้ CubeMX Gererate Initial
ก็ไม่น่าจะผิดพลาดอะไร

ทำตาม Header Files ทุกข้อแล้ว ก็ยังไม่ยอมทำงาน

เช็ค Reference Manual ก็ Initial ครบแล้วนะครับ

งงที่ ทำไมมันวนใน while loop อยู่
และ ขา CLK ไม่ปล่อยออกมาต่อเนื่อง
มัน Pull Down ครั้งแรกครั้งเดียว ที่วิ่งเข้าฟังชั่น
จากนั้น ก็ถูก Pull Up ตาม HW ที่ต่อไว้

งมอยู่ 3 วันเต็มๆ ละ ยังไม่สำเร็จเลย
สโคปนิ่งสนิท
:-[

dec

I2C ปกติขา SCL ก็จ่ายออกมาเฉพาะตอนที่มีการส่งข้อมูลนิครับ ไม่ได้ปล่อยออกมาตลอด

I2C จะเริ่มการส่งโดยการ Generate Start ก่อน คือดึง SDA ลง Low ก่อน เว้นสักพัก SCL ก็จะลง Low ตาม

จากกนั้นก็จะเริ่มการส่งข้อมูล ถ้าขณะนั้นไม่มีข้อมูลส่ง SDA และ SCL จะอยู่ในสภาวะ Low ทั้งคู่

เมื่อส่งเสร็จ ก็ต้อง Generate Stop โดยการ ดึง SDA ขึ้น High ก่อน เว้นสักระยะ แล้วก็ดึง SCL ขึ้น High ตาม


ยืมภาพจาก Google การส่ง Start Stop ใน I2C

ยืมภาพจาก Google การส่งส่งข้อมูล I2C

ปกติ HAL จะครอบการทำงานที่ว่าไว้แล้ว ถ้าอยากจะ test ว่า I2C ใช้ได้รึเปล่าก็ควรใช้ Scope วัดแบบ Single Shot Trigger
หรือไม่ก็ยังไม่ต้องต่อ EEPROM แล้วส่งอะไรก็ได้รัวๆ เพื่อดูสัญญาณครับ

พอดีผมไม่มี f103 เลยเลยช่วยลองไม่ได้ แต่คิดว่าแค่ I2C ตัว CubeMX มันไม่น่าพลาดนะ

TaoTao

ทดลอง มา 3-4 วันเต็มๆ ละ  :-[

คือ พอเรียกฟังชั่น มัน ไปติด while loop นานมากๆ ๆ ๆ ๆ ผิดปกติครับ
เรียก แค่ 3 รอบ รอตั้งนานกว่จะหลุด
ถ้าเรียกรัวๆ คงได้หลับแน่นอน  ;D

ผม Intial Code ด้วย CubeMX ครับ

ครับ อันนี้ โค้ดล่าสุด
วางที่ main ก่อน while(1) loop ครับ



uint8_t my_dat[3] = {1,2,3}, my_get[3] = {0,0,0}, my_stat[5];

my_stat[0] = HAL_I2C_IsDeviceReady(&hi2c1, 0xA1, 10, 10);

HAL_I2C_Mem_Write(&hi2c1, (uint16_t)0xA0, (uint16_t)0, (uint16_t)1, &my_dat[0], 3, 1000);

my_stat[1] = HAL_I2C_IsDeviceReady(&hi2c1, 0xA1, 10, 10);

HAL_I2C_Mem_Read(&hi2c1, (uint16_t)0xA1, (uint16_t)0, (uint16_t)1, &my_get[0], 3, 1000);

my_stat[2] = HAL_I2C_IsDeviceReady(&hi2c1, 0xA1, 10, 10);



ได้  my_stat[0] = 0x02
และ my_stat[1] = 0x02
      my_stat[2] = 0x02 ครับ

อันนี้ Header แจ้งไว้

//--------------------------------------------------------
/** @defgroup I2C_Error_Codes I2C Error Codes 
  * @{
  */
//-------------------------------------------------------- 
#define HAL_I2C_ERROR_NONE      ((uint32_t)0x00)    /*!< No error             */
#define HAL_I2C_ERROR_BERR      ((uint32_t)0x01)    /*!< BERR error           */
#define HAL_I2C_ERROR_ARLO      ((uint32_t)0x02)    /*!< ARLO error           */
#define HAL_I2C_ERROR_AF        ((uint32_t)0x04)    /*!< AF error             */
#define HAL_I2C_ERROR_OVR       ((uint32_t)0x08)    /*!< OVR error            */
#define HAL_I2C_ERROR_DMA       ((uint32_t)0x10)    /*!< DMA transfer error   */
#define HAL_I2C_ERROR_TIMEOUT   ((uint32_t)0x20)     /*!< Timeout error        */



ข้างล่างนี้ เอามาจาก RM0008 ครับ :

//-----------------------------------
Arbitration lost (ARLO)
//-----------------------------------
This error occurs when the I2C interface detects an arbitration lost condition. In this case,
• the ARLO bit is set by hardware (and an interrupt is generated if the ITERREN bit is
set)
• the I2C Interface goes automatically back to slave mode (the MSL bit is cleared). When
the I2C loses the arbitration, it is not able to acknowledge its slave address in the same
transfer, but it can acknowledge it after a repeated Start from the winning master.
• lines are released by hardware


Line are released by Hardware..
อันนี้ ไม่น่าใช่ case ผมนะ
เพราะบัดกรีแน่นหนามาก เช็คเป็น สิบรอบแล้ว T_T!

ไฟล์ภาพ OneShot ขา I2C1_SCL ตอนวิ่งเข้า main ครั้งแรกครับ

เดี๋ยว พรุ่งนี้ ว่าจะไปบ้านหม้อ ซื้อ EEPROM ตัวใหม่ รุ่น/ยี่ห้อ อื่นๆ มาเปลี่ยนดู
จนปัญญาละครับ เผื่อว่าจะ Work

กูเกิล มันแปล "Arbitration lost =  อนุญาโตตุลาการหายไป"
ไปไม่ถูกเลย เดี๋ยวต้องไปถาม ผู้พิพากษา ละ  ;D


TaoTao

Quote from: dec on February 27, 2017, 09:55:08 PM
I2C ปกติขา SCL ก็จ่ายออกมาเฉพาะตอนที่มีการส่งข้อมูลนิครับ ไม่ได้ปล่อยออกมาตลอด

I2C จะเริ่มการส่งโดยการ Generate Start ก่อน คือดึง SDA ลง Low ก่อน เว้นสักพัก SCL ก็จะลง Low ตาม

จากกนั้นก็จะเริ่มการส่งข้อมูล ถ้าขณะนั้นไม่มีข้อมูลส่ง SDA และ SCL จะอยู่ในสภาวะ Low ทั้งคู่

เมื่อส่งเสร็จ ก็ต้อง Generate Stop โดยการ ดึง SDA ขึ้น High ก่อน เว้นสักระยะ แล้วก็ดึง SCL ขึ้น High ตาม


ยืมภาพจาก Google การส่ง Start Stop ใน I2C

ยืมภาพจาก Google การส่งส่งข้อมูล I2C

ปกติ HAL จะครอบการทำงานที่ว่าไว้แล้ว ถ้าอยากจะ test ว่า I2C ใช้ได้รึเปล่าก็ควรใช้ Scope วัดแบบ Single Shot Trigger
หรือไม่ก็ยังไม่ต้องต่อ EEPROM แล้วส่งอะไรก็ได้รัวๆ เพื่อดูสัญญาณครับ

พอดีผมไม่มี f103 เลยเลยช่วยลองไม่ได้ แต่คิดว่าแค่ I2C ตัว CubeMX มันไม่น่าพลาดนะ

อยากรับไปเลี้ยงดูสักบอร์ดไหมครับ ผมมี 2 บอร์ด
เดี๋ยวส่งให้ไปเลย 1 บอร์ด พูดจริงนะครับ
;D

เป็นบอร์ด minium ครับ

az

ชิป EEPROM มีปัญหารึป่าว

ได้ลอง I2C กับ Device อื่นๆ แล้วหรือไม่
เพราะแสวงหา..  มิใช่เพราะรอคอย
เพราะเชี่ยวชาญ..  มิใช่เพราะโอกาส
เพราะสามารถ..  มิใช่เพราะโชคช่วย
ดังนี้แล้ว "ลิขิตฟ้า  หรือจะสู้มานะตน..."

dec

Quote from: TaoTao on February 28, 2017, 12:55:55 AM

อยากรับไปเลี้ยงดูสักบอร์ดไหมครับ ผมมี 2 บอร์ด
เดี๋ยวส่งให้ไปเลย 1 บอร์ด พูดจริงนะครับ
;D

เป็นบอร์ด minium ครับ

ไม่เป็นไรครับ ผมไปยืมบอร์ด stm3210c-eval มาลองดูแล้ว เป็น f107vct6 คล้ายๆ กับ 103 ต่างกันตรงมี ethernet แล้วก็ไม่มี sdio ซึ่งบนบอร์ดมี EEPROM เบอร์ m24c64 อยู่ อันนี้เป็น Code ที่ผมลองแล้วใช้ได้

ไฟล์ m24c64.c
#include "m24c64.h"

static I2C_HandleTypeDef I2C1_Handle;
static uint16_t M24C64_Addr;

/**
  * @brief  I2C Bus initialization
  * @retval None
  */
void M24C64_I2C_Init(uint16_t DevAddr)
{
  GPIO_InitTypeDef  gpioinitstruct = {0}; 

  M24C64_Addr = DevAddr;
 
  __HAL_RCC_GPIOB_CLK_ENABLE();
 
  gpioinitstruct.Pin       = GPIO_PIN_6 | GPIO_PIN_7;
  gpioinitstruct.Mode      = GPIO_MODE_AF_OD;
  gpioinitstruct.Pull      = GPIO_NOPULL;
  gpioinitstruct.Speed     = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOB, &gpioinitstruct);
 
  __HAL_RCC_I2C1_CLK_ENABLE();

  /* Add delay related to RCC workaround */
  while (READ_BIT(RCC->APB1ENR, RCC_APB1ENR_I2C1EN) != RCC_APB1ENR_I2C1EN)
  {
  }
 
  /* Force the I2C Periheral Clock Reset */ 
  __HAL_RCC_I2C1_FORCE_RESET();
     
  /* Release the I2C Periheral Clock Reset */ 
  __HAL_RCC_I2C1_RELEASE_RESET();
 
  I2C1_Handle.Instance              = I2C1;
  I2C1_Handle.Init.ClockSpeed       = 400000;
  I2C1_Handle.Init.DutyCycle        = I2C_DUTYCYCLE_2;
  I2C1_Handle.Init.OwnAddress1      = 0;
  I2C1_Handle.Init.AddressingMode   = I2C_ADDRESSINGMODE_7BIT;
  I2C1_Handle.Init.DualAddressMode  = I2C_DUALADDRESS_DISABLE;
  I2C1_Handle.Init.OwnAddress2      = 0;
  I2C1_Handle.Init.GeneralCallMode  = I2C_GENERALCALL_DISABLE;
  I2C1_Handle.Init.NoStretchMode    = I2C_NOSTRETCH_DISABLE; 

  /* Init the I2C */
  HAL_I2C_Init(&I2C1_Handle);
}

/**
  * @brief  Write a value in a register of the device through BUS.
  * @param  MemAddr: The target memory address
  * @param  pBuffer: The target memory value to be written
  * @param  Length: buffer size to be written
  * @retval None
  */
HAL_StatusTypeDef M24C64_WriteBuffer(uint8_t MemAddr, uint8_t *pBuffer, uint16_t Length)
{
  return HAL_I2C_Mem_Write(&I2C1_Handle, M24C64_Addr, (uint16_t)MemAddr, 16, pBuffer, Length, 3000);
}

/**
  * @brief  Reads multiple data on the BUS.
  * @param  MemAddr: The target memory address
  * @param  pBuffer: pointer to read data buffer
  * @param  Length: length of the data
  * @retval 0 if no problems to read multiple data
  */
HAL_StatusTypeDef M24C64_ReadBuffer(uint8_t MemAddr, uint8_t *pBuffer, uint16_t Length)
{
  HAL_StatusTypeDef status = HAL_OK;

  status = HAL_I2C_Mem_Read(&I2C1_Handle, M24C64_Addr, (uint16_t)MemAddr, 16, pBuffer, Length, 3000);
 
  return status;
}

/**
* @brief  Checks if target device is ready for communication.
* @note   This function is used with Memory devices
* @param  Trials: Number of trials
* @retval HAL status
*/
HAL_StatusTypeDef M24C64_IsDeviceReady(uint32_t Trials)
{
  return (HAL_I2C_IsDeviceReady(&I2C1_Handle, M24C64_Addr, Trials, 3000));
}


ไฟล์ m24c64.h
#ifndef __M24C64_H
#define __M24C64_H

#include "stm32f1xx.h"

#ifdef __cplusplus
extern "C" {
#endif

void M24C64_I2C_Init(uint16_t DevAddr);
HAL_StatusTypeDef M24C64_WriteBuffer(uint8_t MemAddr, uint8_t *pBuffer, uint16_t Length);
HAL_StatusTypeDef M24C64_ReadBuffer(uint8_t MemAddr, uint8_t *pBuffer, uint16_t Length);
HAL_StatusTypeDef M24C64_IsDeviceReady(uint32_t Trials);

#ifdef __cplusplus
}
#endif
 
#endif /* __M24C64_H */


แล้วก็ code ใน main
int main(void)
{
  HAL_Init();

  /* Configure the system clock to 72 MHz */
  SystemClock_Config();


  /* Add your application code here */
  M24C64_I2C_Init(0xA0);
 
  if(M24C64_IsDeviceReady(300) == HAL_OK)
  {
    printf("OK\r\n");
   
    if(M24C64_WriteBuffer(0x0000, SendBuffer, sizeof(SendBuffer)) == HAL_OK)
    {
      M24C64_ReadBuffer(0x0000, RecvBuffer, sizeof(SendBuffer));
    }
    else
    {
      printf("WRITE ERROR\r\n");
    }
  }
  else
  {
    printf("ERROR\r\n");
  }

  /* Infinite loop */
  while (1)
  {
  }
}


ผมไม่ได้ใช้ CubeMX Generate นะ ส่วนตัวไม่ชอบการ Gen project จาก CubeMX

TaoTao

Quote from: dec on February 28, 2017, 12:37:45 PM


ผมไม่ได้ใช้ CubeMX Generate นะ ส่วนตัวไม่ชอบการ Gen project จาก CubeMX

ครับ เดี๋ยวผมจะสร้างเอกสารใหม่ ผ่าน CubeMX
(ใช้ Cube จนเป็นง่อย ลืมวิธีอื่นๆ หมดละ  ;D)

เพื่อให้มัน Include Souce ที่จำเป็น
แต่ไม่ให้มัน Initial pin I2C
เดี๋ยวขอ ไปซื้อ Chip บ้านหม้อก่อน
เผื่อตัวที่ทดลอง เจ๊ง

ครับ ขอบคุณมากมาย ครับ
ขอบคุณทุกๆ คน
:D

TaoTao

ล่าสุด กราฟ ออกสโคปละ
ส่ง DevAddr.. 0xA0 ตามด้วย
    MemAddr  0x00 ตามด้วย
    Data         0x55 ตามด้วย  0xA0

my_dat = 0x55;
my_get = 0x00;

//I2C_HandleTypeDef *hi2c, DevAddress, MemAddress,  MemAddSize, *pData, Size, Timeout
HAL_I2C_Mem_Write( &hi2c1, (uint16_t)0x00A0, (uint16_t)0, (uint16_t)1, &my_dat, 1, 3000);
HAL_I2C_Mem_Read(  &hi2c1, (uint16_t)0x00A1, (uint16_t)0, (uint16_t)1, &my_get, 1, 3000);


สั่ง 0xA1 นี่หว่า
งง  @_@!
:-[