Перейти к содержанию
    

I2C, stm32f4

Я генерирую старт устанавливая бит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 который не работает):

#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:

#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 должен быть проставлен, но он по прежнему ноль.

 

что там может быть еще не так?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

кстати с 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;
}

 

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

 

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

 

немного не ясно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

 

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

 

перепроверил уже почти все комбинации пина:

пуш-пулл, пулл-даун

пуш-пулл, пулл-ап,

опэн-дрэйн, пулл-ап,

опэн-дрэйн, пулл-даун

 

картина одна и таже на осциллографе.

какая комбинация там вообще должна быть?

 

мне кажется чтото не так с клоком, он просто не тикает, но почему? ведь все же настроено правильно.

я пробовал снизить клок периферии (ну и соответственно подправить параметры инициализации I2C), та же фигня.

post-38121-1344005200_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

незнаю, это правда что в этих чипах аппаратный глюк есть на модуле i2c?

Кто нибудь сдесь использовал данный чип с i2c? как его запустить (без использования этой стандартной библиотеки) ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

незнаю, это правда что в этих чипах аппаратный глюк есть на модуле 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!

post-27702-1344083221_thumb.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Жесть!

 

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

 

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

 

 

спасибо большое

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Никак не могу запустить модуль 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:

 

UPDATE

Продолжаю диалог с самим собой)) Все заработало. Неверно было выставлено разрешение осцилла на компе + кривые руки как всегда. Вопрос решен.

Изменено пользователем NaughtyFreak

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...