簡體   English   中英

我是否設置了 I2C CCR 和 TRISE 錯誤? STM32【裸機】

[英]Am I setting I2C CCR and TRISE wrong? STM32 [bare-metal]

按照@wovano 的建議,我將把這個問題簡化。 對於舊版本的問題,請參閱編輯歷史。

概述

我正在嘗試在我的項目( STM32F407ZGT6MMA8452Q加速度計)中包含 I2C,並且我正在設置所有裸機。 我將gschorcht 庫用於加速度計功能。 我目前無法使用示波器或 FT232H。

問題

我不確定我的 I2C 是否正常工作:當我嘗試讀取我的設備 ID 時,我得到的是 0x22 而不是0x2A *。 我也無法循環讀取數據。 如果我使用if (mma845x_new_data (sensor) && mma845x_get_float_data (sensor, &data)) ,我永遠不會得到積極的條件,並且如下調整會迫使我進入Default_Handler: Infinite_Loop進行調試:

void read_data(void)
{
    mma845x_float_data_t  data;
    if (mma845x_new_data (sensor))
    {
        if(mma845x_get_float_data (sensor, &data))
        {
        // max. full scale is +-16 g and best resolution is 1 mg, i.e. 5 digits
        printf("[MMA845X (xyz)[g]] ax=%+7.3f ay=%+7.3f az=%+7.3f\n", data.ax, data.ay, data.az);
        return;
        }
    }
    printf("[not new MMA845X (xyz)[g]] ax=%+7.3f ay=%+7.3f az=%+7.3f\n", data.ax, data.ay, data.az);
}

調試選項卡顯示此跟蹤/斷點陷阱線程: 調試跟蹤/斷點陷阱

我想知道我的 CCR 或 TRISE 設置是否有問題(我包含在我正在使用的計算下方)。 我的SYSCLK為 168MHz, APB1為 42MHz( APB1PRESC = 4),我目前正在測試標准模式

我認為正確的事情

  1. 已正確放置所有上拉電阻
  2. MODER 和 AFR 設置正確
  3. SA0 設置為高或低邏輯電平以匹配設備地址
  4. 從 DR 讀取數據后發送 STOP

代碼

void init_gpio(void)
{
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;    //Port B

    GPIOB->MODER  |= (2U << 12U);   //MMA845_SCL || PB6
    GPIOB->AFR[0] |= (4U << 24U);   //AF4
    GPIOB->OTYPER |= (1U << 6U);    //Output Type to Open Drain
    GPIOB->PUPDR  |= (1U << 12U);   //Set to Pull-Up

    GPIOB->MODER  |= (2U << 14U);   //MMA845_SDA || PB7
    GPIOB->AFR[0] |= (4U << 28U);   //AF4
    GPIOB->OTYPER |= (1U << 7U);    //Output Type to Open Drain
    GPIOB->PUPDR  |= (1U << 14U);   //Set to Pull-Up
}

/*i2c_init*/
void i2c_init(I2C_TypeDef *I2Cx)
{
    /*Enable clock access to I2Cs*/
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; //enable I2C1
//  RCC->APB1ENR |= RCC_APB1ENR_I2C2EN; //enable I2C2
//  RCC->APB1ENR |= RCC_APB1ENR_I2C3EN; //enable I2C3
    RCC->APB1ENR;

    /*Reset I2C*/
    I2Cx->CR1 |= I2C_CR1_SWRST;    /*!BUSY ON */
    I2Cx->CR1 &= ~I2C_CR1_SWRST;   /*!BUSY OFF*/

    int CCR_VAL;
    int TRISE_VAL;
    int MAX_FRQ;

    /*Set I2C frequency same as APB*/
    MAX_FRQ = (SYSCLK/APB1PRESC)/1000000;   //= 42 @ max clock speed
    I2Cx->CR2 &= ~msk(6,0);        /*!BUSY ON*/
    I2Cx->CR2 |= MAX_FRQ;

    if(!MASTER_MODE){
        /* Standard Mode = 100kb/s*/
        /* CCR calculated by half-period of 100k
         * divided by the period of the PCLK
         * CCR = ((1/100'000)/2)/(1/42'000'000)
         * CCR = 5000ns/~24ns = 210
         */
        CCR_VAL = 210;
        /* TRISE calculated by PCLK (in MHz) + 1
         * TRISE = ((42'000'000/1'000'000) + 1)
         * TRISE = 42 + 1 = 43
         */
        TRISE_VAL = 43;
    }
    else
    {
        /*Fast Mode = 400kb/s*/
        if(DUTY_MODE)
        {
            /*16:9 ratio*/
            /* CCR calculated by half-period of 100k
             * divided by the sum of the duty ratios
             * divided by the period of the PCLK
             * t_high = 9 * CCR * TPCLK
             * t_low  = 16 * CCR * TPCLK
             * t_high + t_low = 25 * CCR * TPCLK
             * CCR = ((1/400'000)/2) / (25/42'000'000)
             * CCR = 1250ns/~595ns = 2.1 ~ 2
             */
            CCR_VAL = 2;
        }
        else
        {
            //2:1 ratio
            /* CCR calculated by half-period of 100k
             * divided by the sum of the duty ratios
             * divided by the period of the PCLK
             * t_high = CCR * TPCLK
             * t_low  = 2 * CCR * TPCLK
             * t_high + t_low = 3 * CCR * TPCLK
             * CCR = ((1/400'000)/2) / (3/42'000'000)
             * CCR = 1250ns/~71ns = 17.5 ~ 17
             */
            CCR_VAL = 17;
        }
        /* TRISE calculated by PCLK (in MHz) * 0.3ms + 1
         * TRISE = ((42'000'000/1'000'000)*(300/1000) + 1)
         * TRISE = 42 * 0.3 + 1 = 13.6 ~ 14
         */
        TRISE_VAL = 14;
    }

    /*Set Clock Control value*/
    I2Cx->CCR |= CCR_VAL;   //assuming APB1 = 42MHz, SM = True
    I2Cx->CCR |= (set(DUTY_MODE,I2C_CCR_DUTY_Pos) | set(MASTER_MODE,I2C_CCR_FS_Pos));

    I2Cx->TRISE |= TRISE_VAL;   //assuming APB1 = 42MHz, SM = True
    /*Enable I2C*/
    I2Cx->CR1 |= I2C_CR1_PE;
}

void set_addr(I2C_TypeDef *I2Cx, uint8_t sAddr, const uint8_t *mAddr, int read)
{
    volatile int temp;
    /*Check I2C is not busy*/
    while(I2Cx->SR2 & I2C_SR2_BUSY);

    /*(1) Generate a START, wait for start flag*/
    I2Cx->CR1 |= I2C_CR1_START;
    while (!(I2Cx->SR1 & I2C_SR1_SB));

    /*Transmit slave address + 'write'*/
    I2Cx->DR = sAddr << 1;

    /*Wait for the address flag*/
    while (!(I2Cx->SR1 & I2C_SR1_ADDR));
    temp = I2Cx->SR2; //Clear address flag

    /*Send memory address*/
    //Make sure TXE is emtpy
    while (!(I2Cx->SR1 & I2C_SR1_TXE));
    I2Cx->DR = mAddr;
    //Wait until transmitter is emtpy
    while (!(I2Cx->SR1 & I2C_SR1_TXE));

    if(read)
    {
        /*(2) Generate a START, wait for start flag*/
        I2Cx->CR1 |= I2C_CR1_START;
        while (!(I2Cx->SR1 & I2C_SR1_SB));

        /*Transmit slave address + 'read'*/
        I2Cx->DR = (sAddr << 1) | 1;

        /*Wait for the address flag*/
        while (!(I2Cx->SR1 & I2C_SR1_ADDR));
        temp = I2Cx->SR2; //Clear address flag
    }
}

int i2c_burst_read(I2C_TypeDef *I2Cx, uint8_t sAddr, const uint8_t *mAddr, uint8_t *string, uint32_t size)
{
    if(size == 0)
    {
        return 0;
    }
    uint8_t *pData = string;    //points at the first byte (char) of string
    set_addr(I2Cx, sAddr, mAddr, 1);

    /*Enable ACK*/
    I2Cx->CR1 |= I2C_CR1_ACK;

    while(size > 0U)
    {
        if(size-- == 1)
        {
            /*Disable ACK*/
            I2Cx->CR1 &= ~I2C_CR1_ACK;

            /*Wait until the receive flag is set*/
            while(!(I2Cx->SR1 & I2C_SR1_RXNE));

            //"Generate STOP" was here before

            /*Read data from the DR*/
            *pData++ = I2Cx->DR;
            break;
        }
        else
        {
            /*Wait until the receive flag is set*/
            while(!(I2Cx->SR1 & I2C_SR1_RXNE));

            /*Read data from the DR*/
            *pData++ = I2Cx->DR;
        }
    }
    /*Generate a STOP after receiving*/
    I2Cx->CR1 |= I2C_CR1_STOP;
    return 1;
}

int i2c_burst_write(I2C_TypeDef *I2Cx, uint8_t sAddr, const uint8_t *mAddr, uint8_t *string, uint32_t size)
{
    uint8_t *pData = string;    //points at the first byte (char) of string
    set_addr(I2Cx, sAddr, mAddr, 0);

    while(size > 0U)
    {
        /*Wait for transmitter to be empty*/
        while(!(I2Cx->SR1 & I2C_SR1_TXE));

        I2Cx->DR = *pData++;
        size--;
    }

    /*Wait for byte transfer finished flag*/
    while(!(I2Cx->SR1 & I2C_SR1_BTF));

    /*Generate a STOP after writing*/
    I2Cx->CR1 |= I2C_CR1_STOP;
    return 1;
}

*這可能是因為它是一個“不同的品牌”。 盡管它引起了一些懷疑,即它沒有讀取所有位(二進制中的 0x2A 是0b0010 1010和 0x22 是0b0010 0010 ),但用另一個加速度計測試它會給我 0x05 的值。 有可能會丟失一些位,但我不確定。

你確定你的引腳配置正確嗎? 檢查 GPIOx MODER 寄存器。 如果它不起作用。 您可以查看本教程。 我也使用此代碼。 這里

我認為我的 I2C 通信確實有效! 所以答案是“是的,我的 CCR 和 TRISE”設置是正確的(至少對於 100kHz 模式)。 為了檢查這一點,我借了一個 Arduino 並粘貼了一個簡單的Wire代碼來讀取和寫入線路。 有了它,我發現:

  1. 我可以讀寫 I2C 總線(沒有寄存器地址)
  2. 我在使用注冊地址mAddr時遇到問題
  3. 芯片的ID其實是0x2A

我錯誤地將包含內存地址而不是其內容的變量的地址發送給函數(而不是mAddr = 0x1D ,我將&mAddr作為參數傳遞)。

此外,@wovano 關於 HardFault 的猜測也是正確的。 printf 導致崩潰,要么是因為浮點鏈接,要么是因為它正在讀取一個空變量(因為它沒有獲取任何數據)。

我仍然在從 MMA 讀取數據時遇到問題,因為我的STATUS->ZYXDR標志永遠不會變高( mma845x_new_data(sensor)總是返回 0)。 我的初始化如下,以防有人對飛思卡爾半導體有經驗(圖書館鏈接):

#include "mma845x.h"

#define MMA845X_I2C_ADDRESS_1           0x1c  // SDO pin is low
#define MMA845X_I2C_ADDRESS_2           0x1d  // SDO pin is high

static mma845x_sensor_t* sensor;

void init_MMA_sensor(void)
{
    sensor = mma845x_init_sensor(I2C1, MMA845X_I2C_ADDRESS_2);
    mma845x_config_int_signals(sensor, mma845x_high_active, mma845x_push_pull);
    mma845x_config_hpf(sensor, 0, true);
    mma845x_set_scale(sensor, mma845x_scale_2_g);
    mma845x_set_mode(sensor, mma845x_high_res, mma845x_odr_50, true, false); //make it active!
}

void read_data(void)
{
     mma845x_float_data_t  data;
     if (mma845x_new_data(sensor))
     {
         if(mma845x_get_float_data(sensor, &data))
        {
            // max. full scale is +-16 g and best resolution is 1 mg, i.e. 5 digits
            printf("[MMA845X (xyz)[g]] ax=%+7.3f ay=%+7.3f az=%+7.3f\r\n",
                    data.ax, data.ay, data.az);
            return;
         }
     }
     printf("No new data available\r\n");
}

int main(void)
{
    /*Setup*/
    clock_init_168();
    init_systick_MS(SYSTICK_LOAD_VAL_MS);
    gpio_init();
    uart_init();
    i2c_init(I2C1);
    init_MMA_sensor();

    for(;;)
    {
        read_data();
        delayMS(500);
    }
}

但是最初的問題已經解決了。 感謝您的見解。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM