Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.55/11: Рейтинг темы: голосов - 11, средняя оценка - 4.55
5 / 5 / 2
Регистрация: 02.10.2013
Сообщений: 147

не работает I2C STM32F030

31.08.2020, 09:42. Показов 2663. Ответов 1

Студворк — интернет-сервис помощи студентам
Проц STM32F030K6 под Hal на этой платке все работает, но если честно хочется написать на CMSIS. Порты выбраны везде одинаковые ножки тоже, конфиг ног вроде тоже одинаковый. Перепробовал кучу различных библиотек и различные настройки таймингов, но результат нулевой. Анализатор вообще не видит посылки пакетов, а осциллограф показывает странные уровни, либо это от 3 вольт идет пачка "импульсов" в которой каждый следующий импульс спускается примерно на пол вольта (верх 3 низ 2,5 у следующего 2,5верх низ 2 ну и тд.) либо импульсы "нормальные" но уровень не поднимается выше вольта. Подтяжка есть физическая и обычную включал. Подозреваю, что либо где то забыл включить тактирование (но сравнивал), либо с настройкой тайминга что то не то (высчитывал в Хале)

i2c.c
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#define TIMING_I2C_REG 0x00201D2B // normal 100kHz 100ns Rise 100 Fall tact  8MHz hsi
typedef enum _I2C_Direction {I2C_Transmitter=0, I2C_Receiver=1} I2C_Direction;
void i2c_Init2(void)
{
      // Включить тактирование модуля I2C1
    RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
        RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
    // Настроим выводы PB9, PB10
    // Open drain!
    GPIOA->OTYPER |= GPIO_OTYPER_OT_9 | GPIO_OTYPER_OT_10;
    GPIOA->OSPEEDR |= (GPIO_OSPEEDR_OSPEEDR9 | GPIO_OSPEEDR_OSPEEDR10);
    GPIOA->PUPDR |= (GPIO_PUPDR_PUPDR9_0 | GPIO_PUPDR_PUPDR10_0);
    // Номер альтернативной функции
    GPIOA->AFR[1] |= ((0x04UL<<GPIO_AFRH_AFSEL9_Pos) | (0x04UL<<GPIO_AFRH_AFSEL10_Pos));// В 9 & 10 pin  запишем 4
    GPIOA->MODER |=  ((0x02UL << GPIO_MODER_MODER9_Pos) | (0x02UL << GPIO_MODER_MODER10_Pos));  // В 9, 10 запишем 2
 
 
    // select HSI or SYSCLK
     RCC->CFGR3 &= ~(0x1U << RCC_CFGR3_I2C1SW_SYSCLK_Pos); 
 
    I2C1->CR1 = 0;
 
        I2C1->TIMINGR = (uint32_t)TIMING_I2C_REG;
 
    // Включим модуль
    I2C1->CR1 |= (I2C_CR1_PE); //enable Peripheral
    while ((I2C_BUS->CR1 & I2C_CR1_PE)==0) {};  // Жду пока включится
    // Теперь можно что-нибудь делать
}
 
void I2C_Start_Direction_Adress_Size (I2C_Direction Direction, uint8_t Adress, uint8_t Size)
{
    //I2C_BUS->CR2 &= ~I2C_CR2_AUTOEND;             // Выдавать стоп вручную
    //I2C_BUS->CR2 &= ~I2C_CR2_RELOAD;              // Не использовать режим перезагрузки
    if (Direction) I2C_BUS->CR2 |= I2C_CR2_RD_WRN;  // Режим приёма
    else I2C_BUS->CR2 &= ~I2C_CR2_RD_WRN;           // Режим передачи
    I2C_BUS->CR2 &= ~I2C_CR2_NBYTES;                // Очистить размер данных
    I2C_BUS->CR2 |= Size<<I2C_OFFSET_CR2_NBYTES;    // Установить размер данных
    I2C_BUS->CR2 &= ~I2C_CR2_SADD;  // Очистить адрес ведомого устройства
    I2C_BUS->CR2 |= Adress;         // Установить адрес ведомого устройства
    I2C_BUS->CR2 |= I2C_CR2_START;                  // Выдать старт на шину
    while ((I2C_BUS->ISR & I2C_ISR_BUSY)!=0) {};    // Ожидать выдачу старта
}
 
void I2C_Stop (void)
{
    while(!(I2C1->ISR & I2C_ISR_TXE)){}; // TX buf Empty добавка с форума
    I2C_BUS->CR2 |= I2C_CR2_STOP;               // Выдать стоп на шину
    while (I2C_BUS->ISR & I2C_ISR_BUSY) {};     // Ожидать выдачу стопа
    // Очищаю флаги - необходимо для дальнейшей работы шины
    I2C_BUS->ICR |= I2C_ICR_STOPCF;     // STOP флаг
    I2C_BUS->ICR |= I2C_ICR_NACKCF;     // NACK флаг
    // Если есть ошибки на шине - очищаю флаги
    if (I2C_BUS->ISR & (I2C_ISR_ARLO | I2C_ISR_BERR))
    {
        I2C_BUS->ICR |= I2C_ICR_ARLOCF;
        I2C_BUS->ICR |= I2C_ICR_BERRCF;
    }
}
 
uint8_t I2C_Write_Transaction (uint8_t Adress, uint8_t Register, uint8_t *Data, uint8_t Size)
{
    uint8_t Count=0;    // Счётчик успешно переданных байт
    // Старт
    I2C_Start_Direction_Adress_Size (I2C_Transmitter, Adress, 1+Size);
    // Сейчас либо I2C запросит первый байт для отправки,
    // Либо взлетит NACK-флаг, говорящий о том, что микросхема не отвечает.
    // Если взлетит NACK-флаг, отправку прекращаем.
    while ((((I2C_BUS->ISR & I2C_ISR_TXIS)==0) && ((I2C_BUS->ISR & I2C_ISR_NACKF)==0)) && (I2C_BUS->ISR & I2C_ISR_BUSY)) {};
    if (I2C_BUS->ISR & I2C_ISR_TXIS) I2C_BUS->TXDR=Register;    // Отправляю адрес регистра
    
    // Отправляем байты до тех пор, пока не взлетит TC-флаг.
    // Если взлетит NACK-флаг, отправку прекращаем.
while ((((I2C_BUS->ISR & I2C_ISR_TC)==0) && ((I2C_BUS->ISR & I2C_ISR_NACKF)==0)) && (I2C_BUS->ISR & I2C_ISR_BUSY))
{
        if (I2C_BUS->ISR & I2C_ISR_TXIS) I2C_BUS->TXDR=*(Data+Count++); // Отправляю данные
    }
    I2C_Stop();
    if (Count == Size) return 1; return 0;
}
clock_cfg.h
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include "stm32f0xx.h"                  // Device header
 
#ifndef CLOCK_CFG_H
#define CLOCK_CFG_H
 
//#define EXT_CRYSTAL_EN  // uncomment for enable external quartz
 
/* Uncoment one of SYS_CLOCK_MX */
#define SYS_CLOCK_MX  RCC_CFGR_SW_PLL // System clock mux frof PLL
//#define SYS_CLOCK_MX  RCC_CFGR_SW_HSE // System clock mux frof HSE
//#define SYS_CLOCK_MX  RCC_CFGR_SW_HSI // System clock mux frof HSI
 
/* Предделитель с кварца  работает только если задан EXT_CRYSTAL_EN */
#define PRE_EXT_ENTR_TO_PLL  RCC_CFGR2_PREDIV_DIV1 // USE _DIV1 to _DIV16
 
/* Multiple PLL for stm32f030 and F070 can be high 48 Mhz*/
 
#define PRE_MULTIPLE_PLL  RCC_CFGR_PLLMUL12 //  from _PLLMUL2 to _PLLMUL2  PLL input clock*2
 
/* AHB Prescailer */
 
/*   FLASH-память может работать на максимальной частоте 24 МГц  
    000: Zero wait state, if SYSCLK ? 24 MHz
        001: One wait state, if 24 MHz < SYSCLK ? 48 MHz
*/
#define LATENCY_FLASH (0x1U) // from 0 to 1
 
//AHB prescaler
#define NO_PRESC 0// - без делителя // uncomment for no prescailer for AHB
#define PRE_AHB_KOF  PRE_KOF_AHB_1 //HAL-AHB
#define PRE_KOF_AHB_1            RCC_CFGR_HPRE_DIV1      /*!< SYSCLK not divided */
#define PRE_KOF_AHB_2        RCC_CFGR_HPRE_DIV2      /*!< SYSCLK divided by 2 */
#define PRE_KOF_AHB_4        RCC_CFGR_HPRE_DIV4      /*!< SYSCLK divided by 4 */
#define PRE_KOF_AHB_8        RCC_CFGR_HPRE_DIV8      /*!< SYSCLK divided by 8 */
#define PRE_KOF_AHB_16       RCC_CFGR_HPRE_DIV16     /*!< SYSCLK divided by 16 */
#define PRE_KOF_AHB_64       RCC_CFGR_HPRE_DIV64     /*!< SYSCLK divided by 64 */
#define PRE_KOF_AHB_128    RCC_CFGR_HPRE_DIV128    /*!< SYSCLK divided by 128 */
#define PRE_KOF_AHB_256    RCC_CFGR_HPRE_DIV256    /*!< SYSCLK divided by 256 */
#define PRE_KOF_AHB_512    RCC_CFGR_HPRE_DIV512    /*!< SYSCLK divided by 512 */
 
// APB1 APB1
#define PRE_APB1_KOF PRE_KOF_APB_1 //APB1
 
#define PRE_KOF_APB_1     RCC_CFGR_PPRE_DIV1
#define PRE_KOF_APB_2     RCC_CFGR_PPRE_DIV2
#define PRE_KOF_APB_4     RCC_CFGR_PPRE_DIV4
#define PRE_KOF_APB_8     RCC_CFGR_PPRE_DIV8
#define PRE_KOF_APB_16  RCC_CFGR_PPRE_DIV16
 
/* This setting change MHz to I2C & USART */
// I2C CLOCK MUX Please comment one of this option
#define RCC_I2C1SW          RCC_CFGR3_I2C1SW_HSI            /*!< HSI oscillator clock used as I2C1 clock source */
//#define RCC_I2C1SW        RCC_CFGR3_I2C1SW_SYSCLK   /*!< System clock selected as I2C1 clock source */
 
// USART CLOCK MUX  Please  uncoment one of this
 
#define RCC_USARTSW             RCC_CFGR3_USART1SW_PCLK       /*!< PCLK clock used as USART1 clock source */
//#define RCC_USARTSW           RCC_CFGR3_USART1SW_SYSCLK     /*!< System clock selected as USART1 clock source */
//#define RCC_USARTSW           RCC_CFGR3_USART1SW_LSE        /*!< LSE oscillator clock used as USART1 clock source */
//#define RCC_USARTSW           RCC_CFGR3_USART1SW_HSI        /*!< HSI oscillator clock used as USART1 clock source */
 
uint8_t ClockInit(void);
#endif
clock_cfg.c
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include "clock_cfg.h"
 
//Настраиваем тактирование системы от внешнего кварца
//через PLL на максимально возможных частотах.
//Внешний кварц должен быть на 8МГц
//Возвращает:
//  0 - завершено успешно
//  1 - не запустился кварцевый генератор
//  2 - не запустился PLL
uint8_t ClockInit(void)
{
  __IO int StartUpCounter;
  
  ////////////////////////////////////////////////////////////
  //Запускаем кварцевый генератор
  ////////////////////////////////////////////////////////////
 #ifdef EXT_CRYSTAL_EN 
  RCC->CR |= (1<<RCC_CR_HSEON_Pos); //Запускаем генератор HSE
  
  //Ждем успешного запуска или окончания тайм-аута
  for(StartUpCounter=0; ; StartUpCounter++)
  {
    //Если успешно запустилось, то 
    //выходим из цикла
    if(RCC->CR & (1<<RCC_CR_HSERDY_Pos))
      break;
    
    //Если не запустилось, то
    //отключаем все, что включили
    //и возвращаем ошибку
    if(StartUpCounter > 0x1000)
    {
      RCC->CR &= ~(1<<RCC_CR_HSEON_Pos); //Останавливаем HSE
      return 1;
    }
  }
#else 
// run from internal high-speed OSC 
    RCC->CR |= RCC_CR_HSION; // run HSI
    for(StartUpCounter=0; ; StartUpCounter++)
  {
    //Если успешно запустилось, то 
    //выходим из цикла
    if(RCC->CR & (1<<RCC_CR_HSIRDY_Pos))
      break;
    
    //Если не запустилось, то
    //отключаем все, что включили
    //и возвращаем ошибку
    if(StartUpCounter > 0x1000)
    {
      RCC->CR &= ~(1<<RCC_CR_HSION_Pos); //Останавливаем HSE
      return 1;
    }
  }
    
 #endif 
  ////////////////////////////////////////////////////////////
  //Настраиваем и запускаем PLL
  ////////////////////////////////////////////////////////////
    
    
    
    #ifdef EXT_CRYSTAL_EN
    // от внешнего кварца тактирования предделитель на ПЛЛ может быть разным
    RCC->CFGR |= (RCC_CFGR_PLLSRC_HSE_PREDIV << RCC_CFGR_PLLSRC_Pos);
    // выбираем предделитель
    RCC->CFGR2 |= (RCC_CFGR2_PREDIV_DIV1 << RCC_CFGR2_PREDIV_Pos);
    #else
    //  Если работаем от внутренего тактирования предделитель только 2
     RCC->CFGR |= (RCC_CFGR_PLLSRC_HSI_DIV2 << RCC_CFGR_PLLSRC_Pos);
    #endif
    
    RCC->CFGR |= PRE_MULTIPLE_PLL;
    // Prescailer AHB
    RCC->CFGR |= (PRE_AHB_KOF << RCC_CFGR_HPRE_Pos);
    
 // Prescailer APB1
 RCC->CFGR |= (PRE_APB1_KOF << RCC_CFGR_PPRE_Pos);
 RCC->APB2ENR |= (RCC_APB2ENR_SYSCFGCOMPEN);
    
// USART 
 
RCC->CFGR3 |= (RCC_USARTSW << RCC_CFGR3_USART1SW_Pos);
 
  
  RCC->CR |= (1<<RCC_CR_PLLON_Pos); //Запускаем PLL
  
  //Ждем успешного запуска или окончания тайм-аута
  for(StartUpCounter=0; ; StartUpCounter++)
  {
    //Если успешно запустилось, то 
    //выходим из цикла
    if(RCC->CR & (1<<RCC_CR_PLLRDY_Pos))
      break;
    
    //Если по каким-то причинам не запустился PLL, то
    //отключаем все, что включили
    //и возвращаем ошибку
    if(StartUpCounter > 0x1000)
    {
      RCC->CR &= ~(1<<RCC_CR_HSEON_Pos); //Останавливаем HSE
      RCC->CR &= ~(1<<RCC_CR_PLLON_Pos); //Останавливаем PLL
      return 2;
    }
  }
  
  ////////////////////////////////////////////////////////////
  //Настраиваем FLASH и делители
  ////////////////////////////////////////////////////////////
  
  //Устанавливаем 2 цикла ожидания для Flash
  //так как частота ядра у нас будет 48 MHz < SYSCLK <= 72 MHz
  FLASH->ACR |= (LATENCY_FLASH<<FLASH_ACR_LATENCY_Pos); 
  
 
 
   RCC->CFGR |= (SYS_CLOCK_MX << RCC_CFGR_SW_Pos);//Переключаемся на работу от PLL
 
  
  //Ждем, пока переключимся
  while((RCC->CFGR & RCC_CFGR_SWS_Msk) != (0x02<<RCC_CFGR_SWS_Pos))
  {
  }
  
  //После того, как переключились на
  //внешний источник такирования
  //отключаем внутренний RC-генератор
  //для экономии энергии
    #ifdef EXT_CRYSTAL_EN 
  RCC->CR &= ~(1<<RCC_CR_HSION_Pos);
  #endif
  //Настройка и переклбючение сисемы
  //на внешний кварцевый генератор
  //и PLL запершилось успехом.
  //Выходим
  return 0;
}
main
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "stm32f0xx.h"
#include "I2C.h"
#include "ssd1306.h"
#include "clock_cfg.h"
 
void ssd1306_WriteCommand(uint8_t command)
{
 
    I2C_Write_Transaction(SSD1306_I2C_ADDR,0x00,&command,1);
}
 
int main(void){
    ClockInit();
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
    GPIOA->MODER |= GPIO_MODER_MODER7_0;
    i2c_Init2();
    // моргнули светодиодиком, он моргает это так для успокоения что проц не висит
    GPIOA->BSRR = GPIO_BSRR_BR_7;
     for(int i = 0; i < 1200000; i++);
     GPIOA->BSRR = GPIO_BSRR_BS_7;
    while(1){
        ssd1306_WriteCommand(0xAE);
    }
}
Сильно ногами не бейте, spi шину я победил, но тут руки уже опускаются.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
31.08.2020, 09:42
Ответы с готовыми решениями:

Очередные грабли I2C STM32f030
Не получается читать с EEPROM I2C. При включении первое считывание происходит правильно, а в следующих выводит непонятно что. Причем в...

STM8L - не работает I2C
Помогите домохозяйке сварить борщ - неделю туплю уже - ничего не выходит. На STM8L152K4T6 не заводится аппаратный I2C. К нему подвешен...

STM32F050 I2C не работает
Привет всем. Пытаемся завести на данном проце термодатчик LM75. Собственно до датчика дело не доходит. Не работает сам I2C. ...

1
42 / 35 / 11
Регистрация: 22.09.2017
Сообщений: 125
02.09.2020, 21:16
Бросается в глаза только // Настроим выводы PB9, PB10, в то время как настраиваются выводы PA9 и PA10
Вы подключены к тем линиям на плате?
Остальное на первый взгляд в порядке.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
02.09.2020, 21:16
Помогаю со студенческими работами здесь

Не работает i2c stm32f4
Здравствуйте! Суть проблемы: Соединил по i2c STM32F4-Discovery и датчик температуры BME-280, написал прошивку температура считывается...

Не работает I2C Компас
Здравствуйте. Есть вот такой GPS+компас. Внутри стоит модуль GPS, компас 5883 (QMC или HMC) и какая-то микросхема со затертым...

Не работает I2C на STM8S105C6
Это пример y2s слейва из стандартной библиотеки периферии. #define STM8S105 #include &lt;stm8s.h&gt; #define SLAVE_ADDRESS 0x1F ...

и снова не работает I2C STM32F417
Всем драсте! Возможно тема и баян в стопиццотый раз, но тем не менее.. Никак не могу запустить модуль i2с1 на 417-м стм. Проц lqfp 176,...

STM32VLDISCOVERY + HD44780 + I2C Interface = не работает
Доброго дня! Прошу помощи в вопросе подключения связки STM32VLDISCOVERY к экрану HD44780 посредством I2C интерфейса. Пробовал пример...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
2
Ответ Создать тему
Новые блоги и статьи
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
SDL3 для Web (WebAssembly): Сборка библиотек: SDL3, Box2D, FreeType, SDL3_ttf, SDL3_mixer и SDL3_image из исходников с помощью CMake и Emscripten
8Observer8 27.02.2026
Недавно вышла версия 3. 4. 2 библиотеки SDL3. На странице официальной релиза доступны исходники, готовые DLL (для x86, x64, arm64), а также библиотеки для разработки под Android, MinGW и Visual Studio. . . .
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru