Chapter 13 - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki

13. I2C + ADXL345

โš ๏ธ Sensor Data Not Verified

STM32CubeIDE์—์„œ Build โ†’ Download โ†’ Run๊นŒ์ง€ ์‹ค์ œ NUCLEO-F439ZI์—์„œ ์ˆ˜ํ–‰ํ–ˆ๋‹ค.
๋‹ค๋งŒ ADXL345 I2C module์ด ์—†์–ด์„œ DEVID, X/Y/Z acceleration data๋Š” ์•„์ง ๊ฒ€์ฆํ•˜์ง€ ์•Š์•˜๋‹ค.


Goal

Ch12์—์„œ SPI๋กœ ์—ฐ๊ฒฐํ•˜๋ ค ํ–ˆ๋˜ ADXL345๋ฅผ ์ด๋ฒˆ์—๋Š” I2C1์œผ๋กœ ํ†ต์‹ ํ•œ๋‹ค.

STM32F439ZI
     โ”‚
     โ”‚ I2C1
     โ”‚
     โ”œโ”€โ”€ PB8 โ†’ SCL
     โ””โ”€โ”€ PB9 โ†’ SDA
             โ”‚
             โ–ผ
          ADXL345

์„ค์ •:

I2C      : I2C1
SCL      : PB8
SDA      : PB9
AF       : AF4
Clock    : 16 MHz APB1
Bus Speed: 100 kHz
Mode     : Standard Mode

1. SPI์™€ I2C ์ฐจ์ด

Ch12 SPI:

SCK
MOSI
MISO
CS

Ch13 I2C:

SCL
SDA

I2C์—์„œ๋Š” ์—ฌ๋Ÿฌ slave๊ฐ€ ๊ฐ™์€ ๋‘ ์„ ์„ ๊ณต์œ ํ•˜๊ณ  ์ฃผ์†Œ๋กœ ๊ตฌ๋ถ„๋œ๋‹ค.

Master
  โ”‚
  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ SCL โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€ Slave A
  โ”‚                   โ”œโ”€โ”€โ”€โ”€ Slave B
  โ”‚                   โ””โ”€โ”€โ”€โ”€ Slave C
  โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ SDA โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€

ADXL345์˜ register map ์ž์ฒด๋Š” SPI์™€ I2C์—์„œ ๋™์ผํ•˜๋‹ค.

๋‹ฌ๋ผ์ง€๋Š” ๊ฒƒ์€:

Sensor Register
    โ†“
์–ด๋–ป๊ฒŒ ์ ‘๊ทผํ•˜๋А๋ƒ

์ฆ‰ transport protocol์ด๋‹ค.


2. I2C1 Pin Mapping

์ด๋ฒˆ ์‹ค์Šต:

Pin Function AF
PB8 I2C1_SCL AF4
PB9 I2C1_SDA AF4

4. 100 kHz Timing

ํ˜„์žฌ Bare-Metal project:

APB1 Clock = 16 MHz

Standard Mode:

Target SCL = 100 kHz

๊ธฐ์กด ์‹ค์Šต ๊ณ„์‚ฐ:

CCR = 80

์™œ๋ƒํ•˜๋ฉด Standard Mode์—์„œ๋Š”:

fSCL = fPCLK1 / (2 ร— CCR)

๋”ฐ๋ผ์„œ:

100,000
=
16,000,000 / (2 ร— CCR)

์ •๋ฆฌ:

CCR = 80

TRISE

Standard Mode maximum rise time:

1000 ns

16 MHz clock period:

62.5 ns

๋”ฐ๋ผ์„œ:

TRISE
=
1000 / 62.5 + 1
=
17

๊ฒฐ๊ณผ:

I2C1->CCR   = 80;
I2C1->TRISE = 17;

5. I2C Transaction Flow

I2C์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด๋‹ค.

Write

START
  โ†“
Slave Address + W
  โ†“
ADDR
  โ†“
Register Address
  โ†“
Data
  โ†“
STOP

Register Read

ํŠน์ • register๋ฅผ ์ฝ์„ ๋•Œ:

START
  โ†“
Slave Address + W
  โ†“
Register Address
  โ†“
Repeated START
  โ†“
Slave Address + R
  โ†“
Read Data
  โ†“
NACK
  โ†“
STOP

์ฆ‰ register address๋ฅผ ๋จผ์ € Write ๋ฐฉํ–ฅ์œผ๋กœ ์•Œ๋ ค์ค€ ๋’ค Read ๋ฐฉํ–ฅ์œผ๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ•œ๋‹ค.


6. Practice Code Status

ํ˜„์žฌ ๋ณด์กด๋œ ์›๋ณธ์—์„œ ํ™•์‹คํžˆ ํ™•์ธ๋˜๋Š” ํ•ต์‹ฌ ํ•จ์ˆ˜:

i2c1_init()
i2c1_start()
i2c1_byte_read()

ํ˜„์žฌ Notion์— ํ•จ์ˆ˜ ํ˜ธ์ถœ๋งŒ ๋‚จ์•„ ์žˆ๊ณ  ๋ณธ๋ฌธ์ด ์—†๋Š” ํ•จ์ˆ˜:

i2c1_gpio_init()
i2c1_write_byte()
i2c1_stop()

๋”ฐ๋ผ์„œ ์•„๋ž˜์—์„œ๋Š” ํ™•์ธ๋œ ์ฝ”๋“œ๋งŒ ์›๋ณธ ์ฝ”๋“œ๋กœ ๊ธฐ๋กํ•œ๋‹ค.


7. i2c.h

Wiki์—์„œ๋Š” ํ™•์ธ๋œ ํ•จ์ˆ˜ interface๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ฆฌํ•œ๋‹ค.

#ifndef I2C_H__
#define I2C_H__

#include <stdint.h>
#include "stm32f4xx.h"

/*
 * Initialize I2C1.
 *
 * PB8 โ†’ SCL
 * PB9 โ†’ SDA
 * AF4
 * 100 kHz Standard Mode
 */
void i2c1_init(void);


/*
 * Read one register byte from an I2C slave.
 *
 * saddr:
 *     7-bit slave address
 *
 * maddr:
 *     internal register/sub-address
 *
 * data:
 *     destination for received byte
 */
void i2c1_byte_read(uint8_t saddr,
                    uint8_t maddr,
                    uint8_t *data);

#endif

8. i2c.c โ€” Definitions

#include "i2c.h"

/*
 * ============================================================
 * Timing Configuration
 * ============================================================
 */

/*
 * APB1 clock:
 *
 *     16 MHz
 *
 * Standard Mode target:
 *
 *     100 kHz
 *
 * fSCL = fPCLK1 / (2 ร— CCR)
 *
 * 100 kHz
 * =
 * 16 MHz / (2 ร— 80)
 */
#define I2C_100KHZ            80U


/*
 * Standard Mode maximum rise time:
 *
 *     1000 ns
 *
 * APB1 clock:
 *
 *     16 MHz
 *     = 62.5 ns / cycle
 *
 * TRISE:
 *
 *     1000 / 62.5 + 1
 *     = 17
 */
#define SD_MODE_MAX_RISE_TIME 17U


/*
 * ============================================================
 * Register Bit Definitions
 * ============================================================
 */

/*
 * RCC APB1ENR bit21:
 *
 * I2C1 clock enable.
 */
#define I2C1EN         (1U << 21)


/*
 * CR1 bit0:
 *
 * PE = Peripheral Enable
 */
#define CR1_PE         (1U << 0)


/*
 * CR1 bit8:
 *
 * START generation.
 */
#define CR1_START      (1U << 8)


/*
 * CR1 bit9:
 *
 * STOP generation.
 */
#define CR1_STOP       (1U << 9)


/*
 * CR1 bit10:
 *
 * ACK control.
 */
#define CR1_ACK        (1U << 10)


/*
 * CR1 bit15:
 *
 * Software Reset.
 */
#define CR1_SWRST      (1U << 15)


/*
 * CR2 FREQ field:
 *
 * APB1 clock = 16 MHz
 */
#define CR2_FREQ_16MHZ 16U


/*
 * SR1 bit0:
 *
 * SB = Start Bit generated.
 */
#define SR1_SB         (1U << 0)


/*
 * SR1 bit1:
 *
 * ADDR = Address sent/matched.
 */
#define SR1_ADDR       (1U << 1)


/*
 * SR1 bit6:
 *
 * RXNE = Receive Data Register Not Empty.
 */
#define SR1_RXNE       (1U << 6)


/*
 * SR2 bit1:
 *
 * BUSY = Communication ongoing on the bus.
 */
#define SR2_BUSY       (1U << 1)


/*
 * ============================================================
 * Private Functions
 * ============================================================
 *
 * Their complete archived source body is not present
 * in the current Notion record.
 */
static void i2c1_gpio_init(void);
static void i2c1_start(uint8_t saddr, uint8_t rw);
static void i2c1_write_byte(uint8_t data);
static void i2c1_stop(void);

9. i2c1_init()

void i2c1_init(void)
{
    /*
     * --------------------------------------------------------
     * Step 1. Configure PB8 / PB9
     * --------------------------------------------------------
     *
     * Expected configuration:
     *
     * PB8 โ†’ I2C1_SCL
     * PB9 โ†’ I2C1_SDA
     * AF4
     *
     * The complete body of i2c1_gpio_init()
     * was not preserved in the current Notion source.
     */
    i2c1_gpio_init();


    /*
     * --------------------------------------------------------
     * Step 2. Enable I2C1 Clock
     * --------------------------------------------------------
     *
     * I2C1 is connected to APB1.
     */
    RCC->APB1ENR |= I2C1EN;


    /*
     * --------------------------------------------------------
     * Step 3. Reset I2C Peripheral
     * --------------------------------------------------------
     *
     * SWRST = 1
     *
     * Software-reset the internal I2C logic.
     */
    I2C1->CR1 |= CR1_SWRST;


    /*
     * Release software reset.
     */
    I2C1->CR1 &= ~CR1_SWRST;


    /*
     * --------------------------------------------------------
     * Step 4. Tell I2C Hardware the APB1 Frequency
     * --------------------------------------------------------
     *
     * CR2 FREQ field:
     *
     *     16
     *
     * means:
     *
     *     APB1 = 16 MHz
     *
     * This value is used internally by I2C timing logic.
     */
    I2C1->CR2 = CR2_FREQ_16MHZ;


    /*
     * --------------------------------------------------------
     * Step 5. Configure 100 kHz SCL
     * --------------------------------------------------------
     *
     * Standard Mode:
     *
     *     CCR = 80
     */
    I2C1->CCR = I2C_100KHZ;


    /*
     * --------------------------------------------------------
     * Step 6. Configure Maximum Rise Time
     * --------------------------------------------------------
     *
     * Standard Mode:
     *
     *     TRISE = 17
     */
    I2C1->TRISE = SD_MODE_MAX_RISE_TIME;


    /*
     * --------------------------------------------------------
     * Step 7. Enable I2C1
     * --------------------------------------------------------
     *
     * PE = 1
     */
    I2C1->CR1 |= CR1_PE;
}

10. i2c1_start()

static void i2c1_start(uint8_t saddr, uint8_t rw)
{
    /*
     * --------------------------------------------------------
     * Step 1. Wait Until Bus Is Free
     * --------------------------------------------------------
     *
     * SR2.BUSY:
     *
     *     1 โ†’ bus currently in use
     *     0 โ†’ bus free
     */
    while (I2C1->SR2 & SR2_BUSY)
    {
    }


    /*
     * --------------------------------------------------------
     * Step 2. Enable ACK
     * --------------------------------------------------------
     *
     * ACK is enabled by default before
     * beginning the transaction.
     */
    I2C1->CR1 |= CR1_ACK;


    /*
     * --------------------------------------------------------
     * Step 3. Generate START
     * --------------------------------------------------------
     *
     * Hardware generates the I2C START condition.
     */
    I2C1->CR1 |= CR1_START;


    /*
     * --------------------------------------------------------
     * Step 4. Wait for Start Bit
     * --------------------------------------------------------
     *
     * SR1.SB = 1
     *
     * confirms START has been generated.
     */
    while (!(I2C1->SR1 & SR1_SB))
    {
    }


    /*
     * --------------------------------------------------------
     * Step 5. Send Slave Address + R/W Bit
     * --------------------------------------------------------
     *
     * I2C uses a 7-bit slave address.
     *
     * Transmission byte:
     *
     * [A6 A5 A4 A3 A2 A1 A0 R/W]
     *
     * Therefore:
     *
     *     saddr << 1
     *
     * creates space for R/W in bit0.
     */
    I2C1->DR =
        rw
        ? (uint8_t)((saddr << 1) | 1U)
        : (uint8_t)(saddr << 1);


    /*
     * --------------------------------------------------------
     * Step 6. Wait for Address Phase Complete
     * --------------------------------------------------------
     */
    while (!(I2C1->SR1 & SR1_ADDR))
    {
    }


    /*
     * --------------------------------------------------------
     * Step 7. Clear ADDR Flag
     * --------------------------------------------------------
     *
     * STM32 I2C has a special hardware-defined sequence:
     *
     *     Read SR1
     *        โ†“
     *     Read SR2
     *        โ†“
     *     ADDR cleared
     *
     * The returned values themselves are not needed.
     *
     * The READ operation is required for its
     * hardware side effect.
     */
    (void)I2C1->SR1;
    (void)I2C1->SR2;
}

11. Why saddr << 1?

์˜ˆ๋ฅผ ๋“ค์–ด ADXL345์˜ 7-bit slave address๊ฐ€:

0x53

์ด๋ผ๋ฉด binary:

1010011

I2C address phase์—์„œ๋Š” ๋งˆ์ง€๋ง‰ bit๊ฐ€ R/W๋‹ค.

๊ทธ๋ž˜์„œ:

7-bit address
1010011
   โ†“ << 1
10100110

Write:

10100110

Read:

10100111

์ฆ‰:

(saddr << 1)

๊ณผ:

(saddr << 1) | 1U

๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค.


12. i2c1_byte_read()

ํŠน์ • sensor register๋ฅผ ํ•œ byte ์ฝ๋Š” ํ•ต์‹ฌ ์ฝ”๋“œ๋‹ค.

void i2c1_byte_read(uint8_t saddr,
                    uint8_t maddr,
                    uint8_t *data)
{
    /*
     * ========================================================
     * Phase 1
     * Tell the slave WHICH register we want to read
     * ========================================================
     */


    /*
     * --------------------------------------------------------
     * Step 1. START + Slave Address in WRITE Mode
     * --------------------------------------------------------
     *
     * rw = 0
     *
     * because the first phase sends the sensor's
     * internal register address.
     */
    i2c1_start(saddr, 0U);


    /*
     * --------------------------------------------------------
     * Step 2. Send Sensor Register Address
     * --------------------------------------------------------
     *
     * Example:
     *
     *     maddr = DEVID register address
     *
     * This tells ADXL345 which internal register
     * will be accessed next.
     *
     * The complete archived implementation of
     * i2c1_write_byte() is currently unavailable.
     */
    i2c1_write_byte(maddr);


    /*
     * ========================================================
     * Phase 2
     * Change Direction: WRITE โ†’ READ
     * ========================================================
     */


    /*
     * --------------------------------------------------------
     * Step 3. Generate Repeated START
     * --------------------------------------------------------
     *
     * Important:
     *
     * No STOP is generated between register-address
     * write and data read.
     *
     * This keeps ownership of the bus.
     */
    I2C1->CR1 |= CR1_START;


    /*
     * Wait until Repeated START is generated.
     */
    while (!(I2C1->SR1 & SR1_SB))
    {
    }


    /*
     * --------------------------------------------------------
     * Step 4. Send Slave Address in READ Mode
     * --------------------------------------------------------
     *
     * Address format:
     *
     *     (saddr << 1) | 1
     *
     * LSB = 1
     *
     * means READ.
     */
    I2C1->DR =
        (uint8_t)((saddr << 1) | 1U);


    /*
     * Wait until address phase completes.
     */
    while (!(I2C1->SR1 & SR1_ADDR))
    {
    }


    /*
     * ========================================================
     * Phase 3
     * Receive One Byte
     * ========================================================
     */


    /*
     * --------------------------------------------------------
     * Step 5. Disable ACK Before Receiving Last Byte
     * --------------------------------------------------------
     *
     * This read operation receives exactly ONE byte.
     *
     * Therefore the first byte is also the last byte.
     *
     * ACK = 0 means:
     *
     *     Do not request another byte.
     *
     * The NACK behavior must be prepared BEFORE
     * the final byte is completely received.
     */
    I2C1->CR1 &= ~CR1_ACK;


    /*
     * --------------------------------------------------------
     * Step 6. Clear ADDR
     * --------------------------------------------------------
     *
     * Again:
     *
     * SR1 read
     *   โ†“
     * SR2 read
     *   โ†“
     * ADDR clear
     */
    (void)I2C1->SR1;
    (void)I2C1->SR2;


    /*
     * --------------------------------------------------------
     * Step 7. Generate STOP
     * --------------------------------------------------------
     *
     * Because this is the last receive byte,
     * STOP is prepared before reading DR.
     *
     * The complete archived body of i2c1_stop()
     * is not present in the current source record.
     */
    i2c1_stop();


    /*
     * --------------------------------------------------------
     * Step 8. Wait for Received Data
     * --------------------------------------------------------
     *
     * RXNE = 1
     *
     * means one byte is available in DR.
     */
    while (!(I2C1->SR1 & SR1_RXNE))
    {
    }


    /*
     * --------------------------------------------------------
     * Step 9. Read Data
     * --------------------------------------------------------
     *
     * Store the received sensor register value
     * into the caller's variable.
     */
    *data = (uint8_t)I2C1->DR;
}

13. Repeated START

์™œ START๋ฅผ ๋‘ ๋ฒˆ ์“ฐ๋Š”๊ฐ€?

ํŠน์ • register๋ฅผ ์ฝ์œผ๋ ค๋ฉด ๋จผ์ €:

์–ด๋А register?

๋ฅผ slave์—๊ฒŒ ์•Œ๋ ค์ค˜์•ผ ํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ์ฒซ transaction์€ Write๋‹ค.

START
  โ†“
Slave + W
  โ†“
Register Address

๊ทธ๋‹ค์Œ ์‹ค์ œ data๋ฅผ ์ฝ๊ธฐ ์œ„ํ•ด direction์„ ๋ฐ”๊พผ๋‹ค.

Repeated START
      โ†“
Slave + R
      โ†“
Data

์ „์ฒด:

START
  โ†“
Address + W
  โ†“
Register Address
  โ†“
Repeated START
  โ†“
Address + R
  โ†“
Data
  โ†“
STOP

STOP์„ ์ค‘๊ฐ„์— ๋ณด๋‚ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋‚˜์˜ ์—ฐ๊ฒฐ๋œ register-read transaction์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.


14. Why Read SR1 Then SR2?

์ด ๋ถ€๋ถ„:

(void)I2C1->SR1;
(void)I2C1->SR2;

์€ ๊ฐ’์„ ์–ป๊ธฐ ์œ„ํ•ด ์ฝ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.

STM32 I2C hardware์—์„œ ADDR flag clear ์กฐ๊ฑด์ด:

Read SR1
   โ†“
Read SR2

์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ฆ‰:

register read
=
hardware command ์—ญํ• 

๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

SR2๋ฅผ ์ฝ์ง€ ์•Š์œผ๋ฉด ADDR๊ฐ€ ๊ณ„์† set๋˜์–ด ์ดํ›„ state๊ฐ€ ์ง„ํ–‰๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค.


15. ACK / NACK

Slave๊ฐ€ byte ํ•˜๋‚˜๋ฅผ ๋ณด๋‚ด๊ณ  ๋‚˜๋ฉด master๋Š”:

ACK
โ†’ ๋‹ค์Œ byte ๋” ๋ณด๋‚ด

NACK
โ†’ ์ด์ œ ๊ทธ๋งŒ

์„ ์•Œ๋ ค์ค€๋‹ค.

ํ•œ byte๋งŒ ์ฝ๋Š” ์ด๋ฒˆ ํ•จ์ˆ˜์—์„œ๋Š”:

I2C1->CR1 &= ~CR1_ACK;

๋ฅผ data๋ฅผ ์ฝ๊ธฐ ์ „์— ์ˆ˜ํ–‰ํ•œ๋‹ค.

์™œ๋ƒํ•˜๋ฉด ๋งˆ์ง€๋ง‰ byte์— ๋Œ€ํ•œ NACK timing์„ hardware์— ๋ฏธ๋ฆฌ ์•Œ๋ ค์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.


16. STOP Timing

๋‹จ์ผ byte receive ํ๋ฆ„:

ADDR complete
   โ†“
ACK = 0
   โ†“
ADDR clear
   โ†“
STOP request
   โ†“
RXNE
   โ†“
Read DR

์ฒ˜์Œ ๋ณด๋ฉด:

์•„์ง data๋„ ์•ˆ ์ฝ์—ˆ๋Š”๋ฐ STOP์„ ์™œ ๋ฒŒ์จ ๋ณด๋‚ด์ง€?

๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ์‰ฝ๋‹ค.

ํ•˜์ง€๋งŒ I2C receive์—์„œ๋Š” ACK/NACK ๋ฐ STOP์˜ timing์ด ์‹ค์ œ bus protocol๊ณผ ๋งž์•„์•ผ ํ•ด์„œ ๋งˆ์ง€๋ง‰ byte ์ „์— ์ข…๋ฃŒ ์กฐ๊ฑด์„ ์ค€๋น„ํ•œ๋‹ค.


17. I2C vs SPI โ€” ADXL345

์„ผ์„œ register:

DEVID
POWER_CTL
DATA_FORMAT
DATAX
DATAY
DATAZ

๋“ฑ์€ ๊ทธ๋Œ€๋กœ๋‹ค.

SPI

CS LOW
 โ†“
Command Address
 โ†“
MOSI / MISO
 โ†“
CS HIGH

I2C

START
 โ†“
Slave Address
 โ†“
Register Address
 โ†“
Repeated START
 โ†“
Read
 โ†“
STOP

์ฆ‰:

ADXL345 Driver Logic

๊ณผ:

Communication Transport

๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.


18. Application Layer Status

์ด๋ฒˆ chapter ๋ชฉํ‘œ:

ADXL345
   โ†“
I2C Register Access
   โ†“
DEVID
   โ†“
X/Y/Z
   โ†“
UART

ํ•˜์ง€๋งŒ ํ˜„์žฌ ๋ณด์กด๋œ ๊ธฐ๋ก์—๋Š” I2C low-level ํ•ต์‹ฌ ํ•จ์ˆ˜๋งŒ ์žˆ๊ณ  application ์ „์ฒด source๋Š” ๋‚จ์•„ ์žˆ์ง€ ์•Š๋‹ค.

๋”ฐ๋ผ์„œ:

DEVID Read
X/Y/Z Read
UART Print

์ฝ”๋“œ๋Š” ์žฌ์‹ค์Šต ์‹œ ์‹ค์ œ source ๊ธฐ์ค€์œผ๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค.


19. Build / Run Result

๊ธฐ์กด ์‹ค์Šต ๊ฒฐ๊ณผ:

Build    : PASS
Download : PASS
Run      : PASS

Sensor Data Verification:
NOT COMPLETE

arm-none-eabi-size:

text = 2632 bytes
data = 0 bytes
bss  = 2560 bytes

๊ฒฝ๊ณ  ์—†์ด build๋˜์—ˆ๋‹ค. ์„ผ์„œ๊ฐ€ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— DEVID์™€ acceleration ๊ฐ’ ์ž์ฒด๋Š” ํ™•์ธํ•˜์ง€ ๋ชปํ–ˆ๋‹ค.


20. Hardware Re-Test Plan

Step 1 โ€” Wiring

NUCLEO-F439ZI      ADXL345

PB8  SCL    โ†’      SCL
PB9  SDA    โ†”      SDA

3.3V        โ†’      VCC
GND         โ†’      GND

์‹ค์ œ module์˜ address pin configuration๋„ ํ™•์ธํ•œ๋‹ค.


Step 2 โ€” GPIO

Debugger:

PB8 MODER โ†’ AF
PB9 MODER โ†’ AF

PB8 AF โ†’ 4
PB9 AF โ†’ 4

Step 3 โ€” I2C Timing

ํ™•์ธ:

I2C1->CR2   = 16
I2C1->CCR   = 80
I2C1->TRISE = 17

Step 4 โ€” I2C Enable

ํ™•์ธ:

CR1.PE = 1

Step 5 โ€” First Sensor Test

๊ฐ€์žฅ ๋จผ์ €:

ADXL345 DEVID

๋ฅผ ์ฝ๋Š”๋‹ค.

Expected:

0xE5

DEVID๊ฐ€ ๋งž์œผ๋ฉด:

GPIO configuration
I2C timing
Slave address
START
Address phase
Repeated START
ACK/NACK
Receive

๊ฐ€ ๋Œ€๋ถ€๋ถ„ ์ •์ƒ์ด๋ผ๊ณ  ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.


Step 6 โ€” X/Y/Z

๊ทธ๋‹ค์Œ:

DATAX
DATAY
DATAZ

๋ฅผ ์ฝ๊ณ  UART๋กœ ์ถœ๋ ฅํ•œ๋‹ค.


21. Debugging Checklist

while()์—์„œ ๋ฉˆ์ถ˜๋‹ค๋ฉด ์–ด๋А flag์—์„œ ๋ฉˆ์ท„๋Š”์ง€ ๋จผ์ € ํ™•์ธํ•œ๋‹ค.

BUSY stuck?
โ†’ Bus / wiring ๋ฌธ์ œ

SB not set?
โ†’ START generation ๋ฌธ์ œ

ADDR not set?
โ†’ Slave address / ACK / wiring ๋ฌธ์ œ

ADDR never clears?
โ†’ SR1 โ†’ SR2 read sequence ํ™•์ธ

RXNE not set?
โ†’ Slave response / receive sequence ํ™•์ธ

I2C๋Š” polling loop๊ฐ€ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์—:

์–ด๋А while์—์„œ ๋ฉˆ์ท„๋Š”๊ฐ€?

๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•œ debugging information์ด๋‹ค.


22. Screenshots to Add

ํ˜„์žฌ:

images/ch13_build.png
images/ch13_download.png

์‹ค๊ธฐ ๊ฒ€์ฆ ํ›„:

images/ch13_wiring.jpg
images/ch13_gpio_af.png
images/ch13_i2c_timing.png
images/ch13_devid.png
images/ch13_xyz_uart.png
images/ch13_logic_analyzer.png

๊ฐ€์žฅ ์ค‘์š”ํ•œ ์‹ค๊ธฐ ์ฆ๊ฑฐ:

DEVID = 0xE5

๊ทธ๋ฆฌ๊ณ  ๊ฐ€๋Šฅํ•˜๋ฉด logic analyzer์˜:

START
Address
ACK
Register Address
Repeated START
Data
NACK
STOP

waveform์ด๋‹ค.


23. Key Points

16 MHz APB1
     โ†“
CR2 = 16
     โ†“
CCR = 80
     โ†“
TRISE = 17
     โ†“
100 kHz I2C

๊ทธ๋ฆฌ๊ณ  register read:

START
 โ†“
Slave + W
 โ†“
Register Address
 โ†“
Repeated START
 โ†“
Slave + R
 โ†“
NACK
 โ†“
Data
 โ†“
STOP
  • I2C1์€ PB8=SCL, PB9=SDA, AF4๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์ด๋ฒˆ project๋Š” APB1 16MHz ๊ธฐ์ค€์ด๋‹ค.
  • Standard Mode 100kHz์—์„œ CCR=80, TRISE=17์„ ์‚ฌ์šฉํ•œ๋‹ค.
  • I2C slave address๋Š” 7-bit์ด๊ณ  ์ „์†ก ์‹œ <<1 ํ›„ LSB์— R/W๋ฅผ ๋ถ™์ธ๋‹ค.
  • SB๋Š” START condition ์ƒ์„ฑ ์™„๋ฃŒ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.
  • ADDR๋Š” address phase ์™„๋ฃŒ๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.
  • ADDR clear์—๋Š” SR1 read โ†’ SR2 read ์ˆœ์„œ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • register read๋Š” Write sub-address โ†’ Repeated START โ†’ Read ๊ตฌ์กฐ๋‹ค.
  • single-byte receive์—์„œ๋Š” ๋งˆ์ง€๋ง‰ byte ์ „์— ACK๋ฅผ ๋„๊ณ  STOP์„ ์ค€๋น„ํ•œ๋‹ค.
  • ํ˜„์žฌ ์ƒํƒœ๋Š” build/download/run PASS, sensor data ๋ฏธ๊ฒ€์ฆ์ด๋‹ค.
โš ๏ธ **GitHub.com Fallback** โš ๏ธ