Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: I2C, stm32f4
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
BlackOps
Я генерирую старт устанавливая бит8 в регистре CR1, затем проверяю бит0 в регистре SR1, нот тот бит так и не устанавливается. Вот привожу ниже фрагменты основного кода.


генерирую клоки, системный 168МГц, АПБ1 - 42МГц:
Код
static uint32_t pll_start(uint32_t N, uint32_t M, uint32_t P)
{
    RCC_CR_HSEON_bb = 1;        // enable HSE clock
    flash_latency(168000000ul);    // configure Flash latency for given frequency



    RCC->PLLCFGR = (M << RCC_PLLCFGR_PLLM_bit) |
                   (N << RCC_PLLCFGR_PLLN_bit) |
                   ((P/2-1) << RCC_PLLCFGR_PLLP_bit) |
                   RCC_PLLCFGR_PLLQ_DIV9 |
                   RCC_PLLCFGR_PLLSRC_HSE;    // configure PLL factors,
                                            // always divide USB clock by 9

    RCC->CFGR = RCC_CFGR_PPRE2_DIV2 | // APB2 - divide by 2
                RCC_CFGR_PPRE1_DIV4 | // APB1 - divide by 4,
                RCC_CFGR_HPRE_DIV1;      // AHB - no prescaler,

    while (!RCC_CR_HSERDY_bb);        // wait for stable clock

    RCC_CR_PLLON_bb = 1;            // enable PLL
    while (!RCC_CR_PLLRDY_bb);        // wait for PLL lock

    RCC->CFGR |= RCC_CFGR_SW_PLL;    // change SYSCLK to PLL

    // wait for switch
    while (((RCC->CFGR) & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);

    return 1;
}


тут я настраиваю ножки (для SPI2 и I2C1 который не работает):
CODE

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


uint32_t config_gpio_all(void)
{






//=============================================================================
// GPIOB configuration
//=============================================================================

// enable GPIOB clock
((RCC_TypeDef *)(RCC_BASE))->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;

// Configure GPIOB module
// Alternate Function for SPI2, I2C1
((GPIO_TypeDef *)(GPIOB_BASE))->MODER |=
(GPIO_MODER_MODER13_1 |
GPIO_MODER_MODER15_1 |
GPIO_MODER_MODER9_1 |
GPIO_MODER_MODER8_1 );

// Output type for SPI2, I2C1
((GPIO_TypeDef *)(GPIOB_BASE))->OTYPER |=
(GPIO_OTYPER_OT_8 |
GPIO_OTYPER_OT_9);

// Speed type for SPI2, I2C1
((GPIO_TypeDef *)(GPIOB_BASE))->OSPEEDR |=
(GPIO_OSPEEDER_OSPEEDR13_1 |
GPIO_OSPEEDER_OSPEEDR15_1 |
GPIO_OSPEEDER_OSPEEDR9_1 |
GPIO_OSPEEDER_OSPEEDR8_1 );

// Push/Pull for I2C1, SPI2
((GPIO_TypeDef *)(GPIOB_BASE))->PUPDR |= 0x00;


//((GPIO_TypeDef *)(GPIOB_BASE))->IDR |= RCC_AHB1ENR_GPIOBEN;
//((GPIO_TypeDef *)(GPIOB_BASE))->ODR |= RCC_AHB1ENR_GPIOBEN;
//((GPIO_TypeDef *)(GPIOB_BASE))->BSRRL |= RCC_AHB1ENR_GPIOBEN;
//((GPIO_TypeDef *)(GPIOB_BASE))->BSRRH |= RCC_AHB1ENR_GPIOBEN;
//((GPIO_TypeDef *)(GPIOB_BASE))->LCKR |= RCC_AHB1ENR_GPIOBEN;
//((GPIO_TypeDef *)(GPIOB_BASE))->AFR[1] |= (0x500000 | 0x50000000);

// Alternate Function pin connection for I2C1, SPI2
((GPIO_TypeDef *)(GPIOB_BASE))->AFR[1] |=
((5 << ((13 - 8) << 2)) | // SPI2 SCK, AF5
(5 << ((15 - 8) << 2)) | // SPI2 MOSI, AF5
(5 << ((8 - 8) << 2)) | // I2C1 SCL, AF4
(5 << ((9 - 8) << 2)) ); // I2C1 SDA, AF4





return 0;
}



тут я инициализирую I2C1:
CODE

#include <stdint.h>
#include "inc/stm32f4xx.h"
#include "i2c.h"



uint32_t config_i2c_all(void)
{

//=============================================================================
// I2C1 Related configuration
//=============================================================================
// enable I2C1 clock
((RCC_TypeDef *) (RCC_BASE))->APB1ENR |= RCC_APB1ENR_I2C1EN;





// 1) configure I2C_CR2
((I2C_TypeDef *) (I2C1_BASE)) -> CR2 |= (I2C_CR2_FREQ_5 | I2C_CR2_FREQ_3 |
I2C_CR2_FREQ_1); // APB1 clock is 42MHz

// 2) Configure Clock Control Register, I2C_CCR
// // 100KHz, APB1clk=42MHz, T_high = T_low = (1/42MHz)*210 = 5us
((I2C_TypeDef *) (I2C1_BASE)) -> CCR = 0xd2; // d210

// 3) Configure I2C_TRISE, Rise Time register
((I2C_TypeDef *) (I2C1_BASE)) -> TRISE = 0x2b; // d42 (42 + 1)

// 4) enable I2C1 peripheral
((I2C_TypeDef *) (I2C1_BASE)) -> CR1 |= (I2C_CR1_PE);


return 0;
}



вроде как все просто, стандартный режим, 100КГц, соответственная инициализация, но он во время дебага застревает на первом цикле где я читаю SR1 чтобы проверить бит SB == 1
Код
//=============================================================================
// generating START
//=============================================================================

((I2C_TypeDef *) (I2C1_BASE)) -> CR1 |= I2C_CR1_START;



//=============================================================================
// Check if start bit is set, and writing Slave Address to the DR register
//=============================================================================

// Read SR1, check if SB == 1
while ( !(((tmp0 >> 0) & 0x01) == 1) )
{
tmp0 = ((I2C_TypeDef *) (I2C1_BASE)) -> SR1;
}
tmp0 = 0; // clear


Клок периферии настроен на 42МГц. Это я точно знаю, проверяю даже осциллографом на выходах SPI, там делитель на 8 стоит, и у меня клок 5.25МГц.


А вот I2C даже не запускается, и тут пока проблема не в самом протоколе, а именно в том что само событие СТАРТ не генерируется. В референс мануале например пишется на странице 580 последовательность:

1) загрузить CR2 частотой, и я кладу туда 101010 = 42, т.к. частота периферийного клока 42МГц.

2) сконфигурировать CCR, и я кладу туда: 210, т.к. (1/42МГц) * 210 = 5 микросекунд, что и нужно для 100КГц скорости

3) запрагроммировать TRISE значением на 1МГц больше чем значение частоты в регистре CR2, в моем случае это 42 + 1 = 43

4) и наконец включить сам модуль I2C

Ну и все, после этого как генерируеш старт то бит SB в регистре SR1 должен быть проставлен, но он по прежнему ноль.

что там может быть еще не так?
dac
GPIO то правильно настроены? извиняюсь, не заметил
BlackOps
кстати с GPIO тоже есть вопросы. мне кажется он в начале не совсем был правильно настроен.
вот как он настроен сейчас:
в коментах для удобства привожу в какой режим какой пин ставлю

Код
uint32_t config_gpio_all(void)
{

//=============================================================================
// GPIOB configuration
//=============================================================================

// enable GPIOB clock
((RCC_TypeDef *)(RCC_BASE))->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;

// Configure GPIOB module
// Alternate Function for SPI2, I2C1
((GPIO_TypeDef *)(GPIOB_BASE))->MODER |=
(GPIO_MODER_MODER13_1 | // Alternate Function
GPIO_MODER_MODER15_1 | // Alternate Function
GPIO_MODER_MODER9_1  | // Alternate Function,  I2C1, SDA
GPIO_MODER_MODER8_1  ); // Alternate Function,  I2C1, SCL

// Output type for SPI2, I2C1
((GPIO_TypeDef *)(GPIOB_BASE))->OTYPER |=
(GPIO_OTYPER_OT_8 | // Open-Drain, I2C1, SCL
GPIO_OTYPER_OT_9); // OPen-Drain, I2C1, SDA

// Speed type for SPI2,  (I2C1 is LOW Speed, 2MHz)
((GPIO_TypeDef *)(GPIOB_BASE))->OSPEEDR |=
(GPIO_OSPEEDER_OSPEEDR13_1 |
GPIO_OSPEEDER_OSPEEDR15_1);

// Push/Pull for I2C1, SPI2
((GPIO_TypeDef *)(GPIOB_BASE))->PUPDR |=
(
GPIO_PUPDR_PUPDR8_1 |  // Pull-Down, I2C1, SCL
GPIO_PUPDR_PUPDR9_1    // Pull-Down, I2C1, SDA
);


// Alternate Function pin connection for I2C1, SPI2
((GPIO_TypeDef *)(GPIOB_BASE))->AFR[1] |=
((5 << ((13 - 8) << 2)) |  // SPI2 SCK, AF5
(5 << ((15 - 8) << 2)) |  // SPI2 MOSI, AF5
(5 << ((8 - 8) << 2)) |  // I2C1 SCL, AF4
(5 << ((9 - 8) << 2)) );  // I2C1 SDA, AF4

return 0;
}


но всеравно не работает. Не ставится тот бит после активации события СТАРТ.

и еще, копаюсь тут в интернете, и вижу что почти аналогичная проблема (застой после активации старта) вроде как часто всплывает, и все пишут по разному у кого как сработало.

немного не ясно.
BlackOps
вот я прикрепляю снимок с осциллографа, верхний график SDA нижний SCL.

т.е. Мастер модуль вроде как пытается сгенерить старт пока клок=1, хоть и с большим опозданием, но клок так и не становится активным, почемуто всевремя прижат к нулю. и SDA идет вверх.


пробовал тоже самое просто после того как включил мастер модуль, т.е. без посылки СТАРТа и чего либо. тоже самое. Может чтото не так сконфигурировано всетаки? Может еще чтото там должно быть?

перепроверил уже почти все комбинации пина:
пуш-пулл, пулл-даун
пуш-пулл, пулл-ап,
опэн-дрэйн, пулл-ап,
опэн-дрэйн, пулл-даун

картина одна и таже на осциллографе.
какая комбинация там вообще должна быть?

мне кажется чтото не так с клоком, он просто не тикает, но почему? ведь все же настроено правильно.
я пробовал снизить клок периферии (ну и соответственно подправить параметры инициализации I2C), та же фигня.
BlackOps
незнаю, это правда что в этих чипах аппаратный глюк есть на модуле i2c?
Кто нибудь сдесь использовал данный чип с i2c? как его запустить (без использования этой стандартной библиотеки) ?
adnega
Цитата(BlackOps @ Aug 4 2012, 07:10) *
незнаю, это правда что в этих чипах аппаратный глюк есть на модуле i2c?
Кто нибудь сдесь использовал данный чип с i2c? как его запустить (без использования этой стандартной библиотеки) ?


Работает.

Код
    RCC->APB1ENR = (1 << RCC_APB1_I2C1);
    RCC->APB2ENR = (1 << RCC_APB2_SYSCFG);
    RCC->AHB1ENR = (1 << RCC_AHB1_PORTB);
    GPIOB->MODER =
          (GPIO_MODE_ALTERNATE    << GPIO_MODER_PIN8)
        | (GPIO_MODE_ALTERNATE    << GPIO_MODER_PIN9);
    GPIOB->AFR[1] =
            (AF_PB8_I2C1_SCL    << GPIO_AFR1_PIN8)
        |    (AF_PB9_I2C1_SDA    << GPIO_AFR1_PIN9);

    GPIOB->OTYPER = (1 << 8) | (1 << 9);

    I2C1->CR1 = (0 << I2C_CR1_PE);
    I2C1->CR2 =
          (I2C_FREQ_42MHZ << I2C_CR2_FREQ)
        | (1 << I2C_CR2_ITEVTEN);
    I2C1->CCR = I2C_FREQ_42MHZ * 1000000 / 2 / I2C_SPD;
    I2C1->CR1 = (1 << I2C_CR1_PE);

    // start
    con_str("[START]");
    I2C1->CR1 |= (1 << I2C_CR1_START);
    while((I2C1->SR1 & (1 << I2C_SR1_SB)) == 0);

    // devsel
    con_str("[DEVSEL]");
    I2C1->SR1;
    I2C1->DR = 0xA0;
    while((I2C1->SR1 & (1 << I2C_SR1_ADDR)) == 0);
    I2C1->SR1;
    I2C1->SR2;
    con_str("[DOK]");

    // wr-addrh
    while((I2C1->SR1 & (1 << I2C_SR1_TXE)) == 0);
    con_str("[WR ");
    con_byte(0x00);
    con_str("]");
    I2C1->DR = 0x00;

    // wr-addrl
    while((I2C1->SR1 & (1 << I2C_SR1_TXE)) == 0);
    con_str("[WR ");
    con_byte(0x00);
    con_str("]");
    I2C1->DR = 0x00;

    // r-start
    con_str("[R-START]");
    I2C1->CR1 |= (1 << I2C_CR1_START);
    while((I2C1->SR1 & (1 << I2C_SR1_SB)) == 0);

    // devsel
    con_str("[DEVSEL]");
    I2C1->SR1;
    I2C1->DR = 0xA1;
    while((I2C1->SR1 & (1 << I2C_SR1_ADDR)) == 0);
    I2C1->CR1 |= (1 << I2C_CR1_ACK);
    I2C1->SR1;
    I2C1->SR2;
    con_str("[DOK]");

    // rd
    while((I2C1->SR1 & (1 << I2C_SR1_RXNE)) == 0);
    I2C1->CR1 &= ~(1 << I2C_CR1_ACK);
    con_str("[RD ");
    con_byte(I2C1->DR);
    con_str("]");

    // rd
    while((I2C1->SR1 & (1 << I2C_SR1_RXNE)) == 0);
    con_str("[RD ");
    con_byte(I2C1->DR);
    con_str("]");

    // stop
    while((I2C1->SR1 & (1 << I2C_SR1_TXE)) == 0);
    con_str("[STOP]");
    I2C1->CR1 |= (1 << I2C_CR1_STOP);


Код
// Alternate Function pin connection for I2C1, SPI2
((GPIO_TypeDef *)(GPIOB_BASE))->AFR[1] |=
((5 << ((13 - 8) << 2)) | // SPI2 SCK, AF5
(5 << ((15 - 8) << 2)) | // SPI2 MOSI, AF5
(5 << ((8 - 8) << 2)) | // I2C1 SCL, AF4
(5 << ((9 - 8) << 2)) ); // I2C1 SDA, AF4


Для I2C AF=4, а не 5!
BlackOps
Жесть!

я знаю что для i2c он висит на AF4 а не AF5! И даже в комментах своих прописал, но всеравно не проставил!

ВОбщем, исправил это, посмотрел на Ваш код, сделал еще пару исправлений в своем коде, и заработало.


спасибо большое
NaughtyFreak
Дабы не плодить новой темы...

Никак не могу запустить модуль i2с1 на 417-м стм. Проц lqfp 176, модуль висит на GPIOB 8 и 9.
Дебагером дохожу до старт бита, на этом всё заканчивается. при попытке что-то записать в DR уходит в несознанку и выкидывает флаг BUSY. Осциллом кажет что SDA прижата, на SCL прижимает и всё...
Код:
Код
       #include "stm32f4xx.h"
    #include "stdio.h"
    
    #define MPU_6050_address_write 0xD0
    #define MPU_6050_address_read 0xD1
  
    //-----------------------------------------------------------------------------------------------
    void Delay (unsigned int time)
    {
     unsigned int temp;    
     for (temp=time;temp>0;temp--);    
  }
     void Init_GPIOB (void)
    {
        RCC->AHB1ENR|=RCC_AHB1ENR_GPIOBEN; // подаем клок на порт В
        /*
        .
        . Insert GPIOB code here
        .
        .
        */
    }
    
    
    void Init_I2C1 (void)
    {
        GPIOB->MODER|=(GPIO_MODER_MODER8_1|GPIO_MODER_MODER9_1); // PB8, PB9 as I2C1
        GPIOB->OTYPER|=(GPIO_OTYPER_OT_8|GPIO_OTYPER_OT_9);
        GPIOB->OSPEEDR|=(GPIO_OSPEEDER_OSPEEDR8_1|GPIO_OSPEEDER_OSPEEDR9_1); // 50 MHz GPIOB clock speed
        GPIOB->AFR[1]|=4; //PB8 SCL
        GPIOB->AFR[1]|=(4<<4); //PB9 SDA
        
        RCC->APB1ENR|=RCC_APB1ENR_I2C1EN; //Enable clock
        RCC->APB1RSTR|=RCC_APB1RSTR_I2C1RST; //reset I2C1
        RCC->APB1RSTR&=~(RCC_APB1RSTR_I2C1RST); //set I2C1
        I2C1->CR1&=~I2C_CR1_PE;//disable all I2C peripherial
        I2C1->CR2|=0x002A; //Fclk1 = 42 MHz
        I2C1->CCR|=(1<<15)|(1<<14);//fast mode, 400 KHz duty cycle
        I2C1->CCR|=0x05; //Tscl = 2970 ns ~ < 400 KHz
        I2C1->TRISE|=0x0E; //Rise time 300ns
        I2C1->CR1|=I2C_CR1_PE;//enable all I2C peripherial
    }
    
    /*-------------------------------------------------------------------------------*/
    
    void I2C1_Start (void)
    {
        I2C1->CR1|=I2C_CR1_START;
  }
    
    //--------------------------------------------------------------------------------
    void MPU6050_Init (unsigned char *data)
    {
        I2C1_Start();
        while (!(I2C1->SR1&I2C_SR1_SB)); // ждём установки старт бита..
         (void) I2C1->SR1; // читаем статус регистер
           I2C1->DR=MPU_6050_address_write; // на этом всё умирает!!!
            while(!(I2C1->SR1 & I2C_SR1_ADDR)) {};
                    (void) I2C1->SR1;
                    (void) I2C1->SR2;
                     I2C1->DR=0x75;
                while (!(I2C1->SR1&I2C_SR1_BTF)) {};
                            
      I2C1_Start();
       while (!(I2C1->SR1&I2C_SR1_SB));
           (void) I2C1->SR1;                            
              I2C1->DR=MPU_6050_address_read;
                    (void) I2C1->SR1;
                    (void) I2C1->SR2;
                 while (!(I2C1->SR1&I2C_SR1_RXNE));    
                    
      *data=I2C1->DR;
      I2C1->CR1|=I2C_CR1_STOP;                            
  }
    //--------------------------------------------------------------------------------
    void Send_Data_I2C (unsigned char data)
    {
        
  }
    
    int main (void)
{
     unsigned char mpu_reg;
     SystemInit(); // стандартная функция для СТМ32, клок ядра 168 МГц, 42 МГц клок АРВ1
     Init_GPIOB();
     Init_I2C1();
     MPU6050_Init (&mpu_reg);
     //I2C1_Start();    
     while (1);
     return 0;
    
}


На шине висит модуль MPU-6050 (3D motion processor). Не думаю что проблема в неём, т.к. он аппаратно залочен на слейв.
Какие догдаки: возможно намудрил в регистрах CCR и TRISE, но с другой стороны тогда всё равно хоть что-нибудь было бы на линии данных. Такое ощущение что модуль после старт бита подвисает. Вобщем у кого есть опыт, прошу помощи зала.
Если у кого-то есть рабочий код I2C мастер на 400 КГц, выложите пжлст, сам тогда буду копаться-анализировать свои баги.
З.Ы. Эррату читал, там по моему вопросу ничего нету.. Код недописан, на мусор не обращайте внимание.

UPDATE:

Отключил гиру от проца, прошёлся осциллом (линии подтянуты к vcc +3.3v), при генерации старта проц опускает обе линии к земле вместо только SDA. я в полном замешательстве. Это что же получается, глюк уже аппаратный?
NaughtyFreak
Разобрался. Оказался аппаратный косяк проца, лечится заменой оного на рабочий. Такие дела crying.gif

UPDATE
Продолжаю диалог с самим собой)) Все заработало. Неверно было выставлено разрешение осцилла на компе + кривые руки как всегда. Вопрос решен.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.