Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ARM, Cortex, STM32
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
-26 / 4 / 0
Регистрация: 26.09.2024
Сообщений: 128

Передача данных по i2c через DMA STM32F401CUE6

08.10.2025, 13:46. Показов 4768. Ответов 95
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день. При попытки передать данные на устройство по i2c через DMA нифига не выходит, DMA не в какую не хочет работать.

Адрес устройства определяется как надо, условие Старт и отправка адреса тоже происходит нормально но DMA не стартует и нет прерывания от DMA.
В отладке видно что бит DMA1_Stream6->CR |= DMA_SxCR_EN; устанавливается.
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
I2C_HandleTypeDef hi2c1;
 
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
void DMA_Init(void);
uint8_t st7567a_IsDeviceReady(I2C_HandleTypeDef i2c);
void DMA_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pBuffer, uint8_t size);
void I2C_write(I2C_HandleTypeDef *hi2c, uint8_t Addr, uint8_t *pBuffer, uint16_t size);
//==============================================================================================================================
 
uint8_t addr_i2c;
uint8_t Buffer[10] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xFF};
//==============================================================================================================================
 
void DMA_Init(void)
{
  __enable_irq ();
  RCC->AHB1ENR|=RCC_AHB1ENR_DMA1EN;
  DMA1_Stream6->CR = 0 ;
  DMA1_Stream6->CR |= DMA_CHANNEL_6;
  DMA1_Stream6->CR |= DMA_SxCR_MINC;
  DMA1_Stream6->CR |= DMA_SxCR_DIR_0;
  DMA1_Stream6->CR |= DMA_SxCR_TCIE | DMA_SxCR_HTIE | DMA_SxCR_TEIE | DMA_SxCR_DMEIE;
  HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
}
//==============================================================================================================================
 
uint8_t st7567a_IsDeviceReady(I2C_HandleTypeDef i2c)
{
    for(uint8_t i = 0; i < 255; i++)
    {
        HAL_Delay(10);
        if(HAL_I2C_IsDeviceReady(&i2c, i, 3, 100) == HAL_OK)
        {
            return i;
        }
    }
    return 0;
}
//==============================================================================================================================
 
void DMA1_Stream6_IRQHandler(void)
{
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    if(DMA1->HISR & DMA_HISR_TCIF6)
    {
        DMA1->HIFCR &= ~ DMA_HIFCR_CTCIF6;
        DMA1_Stream6->CR&=~DMA_SxCR_EN;
        uint8_t temp __attribute__((unused)) = hi2c1.Instance->SR1 | hi2c1.Instance->SR2;
        hi2c1.Instance->CR1 |= I2C_CR1_STOP;
        while( !( hi2c1.Instance->CR1 & I2C_CR1_STOP )) ;
    }
    else if(DMA1->HISR & DMA_HISR_HTIF6)
        {
        DMA1->HIFCR &= ~ DMA_HIFCR_CHTIF6;
        }
    else if(DMA1->HISR & DMA_HISR_TEIF6)
            {
        DMA1->HIFCR &= ~ DMA_HIFCR_CTEIF6;
            }
    else if(DMA1->HISR & DMA_HISR_DMEIF6)
            {
        DMA1->HIFCR &= ~ DMA_HIFCR_CDMEIF6;
            }
}
 
//==============================================================================================================================
uint8_t tmp = 1;
void DMA_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pBuffer, uint8_t size)
{
    DMA1_Stream6->M0AR = (uint32_t)pBuffer;
    DMA1_Stream6->PAR=(uint32_t)&hi2c->Instance->DR;
    DMA1_Stream6->NDTR = size;
    hi2c->Instance->CR2 |= I2C_CR2_DMAEN;
    DMA1_Stream6->CR |= DMA_SxCR_EN;
    tmp = 2;
}
//==============================================================================================================================
 
void I2C_write(I2C_HandleTypeDef *hi2c, uint8_t Addr, uint8_t *pBuffer, uint16_t size)
{
    while(hi2c->Instance->SR2&I2C_SR2_BUSY){;}
    hi2c->Instance->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
    while( !( hi2c->Instance->SR1 & I2C_SR1_SB )){;}
    hi2c->Instance->DR = Addr;
    while( !( hi2c->Instance->SR1 & I2C_SR1_ADDR )){;}
    DMA_Transmit(hi2c, pBuffer, size);
}
 
int main(void)
{
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
DMA_Init();
addr_i2c = st7567a_IsDeviceReady(hi2c1);
I2C_write(&hi2c1, addr_i2c, Buffer, 10);
while (1)
{
}
}
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 15;
  RCC_OscInitStruct.PLL.PLLN = 72;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
 
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_I2C1_Init(void)
{
 
  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET);
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
                          |GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
                          |GPIO_PIN_12|GPIO_PIN_15, GPIO_PIN_RESET);
 
  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10
                          |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15
                          |GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET);
 
  /*Configure GPIO pins : PC13 PC14 PC15 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
  /*Configure GPIO pins : PA0 PA1 PA2 PA3
                           PA4 PA5 PA6 PA7
                           PA8 PA9 PA10 PA11
                           PA12 PA15 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
                          |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7
                          |GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
                          |GPIO_PIN_12|GPIO_PIN_15;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
  /*Configure GPIO pins : PB0 PB1 PB2 PB10
                           PB12 PB13 PB14 PB15
                           PB3 PB4 PB8 PB9 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_10
                          |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15
                          |GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_8|GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
  /*Configure GPIO pin : PB5 */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
}
void Error_Handler(void)
{
  __disable_irq();
  while (1)
  {
  }
}
Добавлено через 55 минут
Нашёл ошибку DMA1_Stream6->CR |= DMA_CHANNEL_6; исправил на DMA1_Stream6->CR |= DMA_CHANNEL_1; как в таблице всё равно не хочет заводиться.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
08.10.2025, 13:46
Ответы с готовыми решениями:

ADC->DMA->SDIO (или NAND через FSMC) без остановки в обработчике прерываний DMA на STM32F407VG, реально или нет?
Добрый день. Столкнулся с необходимостью писать большой объём данных АЦП с высокой скоростью....

USART2(RX+IDLE+DMA)+USART3(TX DMA)
Принимаю по юсарт2, побайтно, на скрости 115200. Пытаюсь передавать по юсарт3 через DMA, скорость...

STM32F4Discovery - ADC DMA и FSMC DMA
Привет всем. Вынужден опять обратиться за Вашей помощью :) Ситуация такая. 1. Дисплей...

95
-26 / 4 / 0
Регистрация: 26.09.2024
Сообщений: 128
09.10.2025, 13:38  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Dushevny Посмотреть сообщение
Да, на случай помех в связи или сброса (перезапуска) ведущего посреди обмена
Да понял, у меня DMA зависает и бит DMA_SxCR_EN не хочет устанавливаться в ноль.
0
349 / 147 / 10
Регистрация: 19.07.2024
Сообщений: 825
09.10.2025, 13:41
Цитата Сообщение от MechanicVV Посмотреть сообщение
Корочи i2c в STM32 дрянь полная, нужно после каждой передачи одного пакета ОДНОГО сбрасывать полностью весь модуль i2c, а это значит что его придётся заново инициализировать и так каждый раз.
Бред. Работаю на STM32F4xx по I2C с кучей ведомых и много передач подряд. Как по DMA так и без. Ничего не сбрасываю и не переинициализирую.
0
1516 / 532 / 77
Регистрация: 22.09.2023
Сообщений: 1,694
09.10.2025, 13:42
Цитата Сообщение от MechanicVV Посмотреть сообщение
бит DMA_SxCR_EN не хочет устанавливаться в ноль
А разве такое возможно вообще?
0
349 / 147 / 10
Регистрация: 19.07.2024
Сообщений: 825
09.10.2025, 13:44
Цитата Сообщение от MechanicVV Посмотреть сообщение
Да понял, у меня DMA зависает и бит DMA_SxCR_EN не хочет устанавливаться в ноль.
Значит нужно искать баги в своём коде, а не валить на контроллер. Он в ваших багах не виноват.
0
-26 / 4 / 0
Регистрация: 26.09.2024
Сообщений: 128
09.10.2025, 14:39  [ТС]
Цитата Сообщение от Dushevny Посмотреть сообщение
А разве такое возможно вообще?
Проверил всё таки поток отрабатывает как надо но похоже МК зависает в прирывании.

Добавлено через 29 минут
Всё разобрался, совсем забыл про сброс флагов DMA вот этих
DMA1->HIFCR =0xFFFFFFFF;
DMA1->LIFCR =0xFFFFFFFF;
Добавлено через 27 секунд
Цитата Сообщение от jcxz Посмотреть сообщение
Значит нужно искать баги в своём коде
Всё нашёл.

Добавлено через 5 минут
Теперь хоть знаю как DMA юзать всё никак руки не доходили разобраться.
0
349 / 147 / 10
Регистрация: 19.07.2024
Сообщений: 825
09.10.2025, 15:18
Цитата Сообщение от MechanicVV Посмотреть сообщение
сброс флагов DMA вот этих
DMA1->HIFCR =0xFFFFFFFF;
DMA1->LIFCR =0xFFFFFFFF;
Так делать некорректно. Таким образом вы нарушаете работу соседних каналов DMA. Сбрасывать нужно только флаги своего DMA-канала, не трогая чужие.
Да - сейчас у вас наверное используется только один DMA-канал, и потому оно работает. Но завтра же захотите ещё один канал DMA и снова будете писать "Сбоит DMA". Хотя проблема будет опять в вашем коде.
1
-26 / 4 / 0
Регистрация: 26.09.2024
Сообщений: 128
09.10.2025, 15:26  [ТС]
jcxz, это да я потом исправлю.
0
-26 / 4 / 0
Регистрация: 26.09.2024
Сообщений: 128
10.10.2025, 08:43  [ТС]
jcxz, в случаи фигни на линии i2c товарищ Dushevny, предложил идею двух регистров, как вы считаете на сколько такая идея работоспособна или можно ещё добавить какой нибудь костыль?
C++
1
2
3
4
5
6
7
8
9
10
if((Hw->SR2 & I2C_SR2_BUSY) && !(Hw->CR1 & I2C_CR1_STOP))
    {
        // this function must set I2C_SCL to open drain output mode,
        // generate 9 clock cycles and return I2C_SCL to AF open drain mode
        // to flush possible unread zero-bits (which are pulling SDA low) from slave
        extern void generate_9_i2c_clocks();
 
        Hw->CR1 = 1 * I2C_CR1_SWRST;                // restart to prevent hang-up (sometimes unable to generate START)
        generate_9_i2c_clocks();
    }
0
 Аватар для COKPOWEHEU
4149 / 2727 / 433
Регистрация: 09.09.2017
Сообщений: 12,086
10.10.2025, 10:06
Цитата Сообщение от VladimirU Посмотреть сообщение
В кубе хотя бы есть графонистый конфигуратор тактового генератора который очень облегчает старт жирного МК.
Я-то думал, основным преимуществом Куба выдают графическую конфигурялку выводов. Даже простенький аналог написал. А теперь про тактирование говорите.
Проблема в том, что я с Кубом не работал и не знаю как это там выглядит.
Цитата Сообщение от wizard41 Посмотреть сообщение
Проблема с IDE кубом в другом: если начинающие к нему привыкают - потом сложно будет переучиваться на более профессиональные среды
Или на другие камни, не от ST.
Цитата Сообщение от MechanicVV Посмотреть сообщение
что такое чисты Си я и не знаю но догадываюсь, а вот что такое грязный Си это однако вопрос.
Возможно, чтобы не путать с С++, С# или, того хуже, с 1С.
0
Нарушитель
445 / 886 / 106
Регистрация: 23.11.2021
Сообщений: 5,204
Записей в блоге: 19
10.10.2025, 13:09
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Даже простенький аналог написал.
А как им пользоваться? Тыкал-тыкал мышей в клеточки - вообще ничего не происходит.

Добавлено через 40 секунд
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
чтобы не путать
Чаще всего я встречал термин "чистый С" в отношении baremetal-разработки. То бишь не оскверненный всякой дрянью.
0
 Аватар для COKPOWEHEU
4149 / 2727 / 433
Регистрация: 09.09.2017
Сообщений: 12,086
10.10.2025, 13:16
Цитата Сообщение от Eddy_Em Посмотреть сообщение
А как им пользоваться? Тыкал-тыкал мышей в клеточки - вообще ничего не происходит.
Три последних столбца таблицы доступны для редактирования. Цвет, отображаемое имя пина и комментарий. Еще галочки сверху чтобы убирать ненужную периферию
0
349 / 147 / 10
Регистрация: 19.07.2024
Сообщений: 825
10.10.2025, 13:54
Цитата Сообщение от MechanicVV Посмотреть сообщение
jcxz, это да я потом исправлю.
Это хорошо, что вы это понимаете. Но ведь вы не написали этого в том сообщении. А завтра его читает новичок, с похожей проблемой. И он просто тупо копипастит ваш код. Потому что считает его рабочим решением. Вы же его выложили с таким описанием, как будто тот код решает проблему.

Добавлено через 19 минут
Цитата Сообщение от MechanicVV Посмотреть сообщение
товарищ Dushevny, предложил идею двух регистров, как вы считаете на сколько такая идея работоспособна
Что за "идея 2-х регистров"? Не понял.

Если что: Мой I2C-драйвер в проекте с STM32F429 построен на простом конечном автомате (в ISR). Он работает с 5-ю ведомыми, сидящими на единой шине I2C. С некоторыми - через DMA (там, где большие транзакции), с некоторыми - через программный I/O внутри ISR (если транзакции короткие). Ни Куб ни HAL - не использую. Вся работа - исключительно на регистрах. Работа автомата состояний драйвера I2C осуществляется внутри 4-х ISR: 2-х ISR от I2C-периферии + 2-х от DMA-контроллера. Костылей нет. Зачем они там? Без них всё прекрасно работает. Согласно RM на МК.

Единственное что может быть подобно костылю в моём коде: При старте прошивки, на SCL/SDA подаю серию импульсов (ногодрыгом) для завершения всех незавершённых пересылок во всех I2C-слэйвах. Это на случай, если старт программы произошёл после перезапуска устройства во время пересылки по I2C (незавершённой). Но если это называть "костылём", то он не для I2C микроконтроллера, а для автоматов состояний I2C в ведомых. Для их сброса. И делаю такое не только на STM32F4xx, но и на других МК.
0
62 / 187 / 31
Регистрация: 14.02.2013
Сообщений: 1,717
10.10.2025, 20:24
COKPOWEHEU, ой не знаю все куб обсерают ОХ как зря.

Добавлено через 4 минуты
Выкладываю для истории да и сам когда нибудь вернусь
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
void DMA1_Stream6_IRQHandler(void)
{
 if(DMA1->HISR & DMA_HISR_TCIF6)
 {
 DMA1->HIFCR |= DMA_HIFCR_CTCIF6;
 while(( hi2c1.Instance->CR1 & I2C_SR1_BTF)){;}
 hi2c1.Instance->CR1 |= I2C_CR1_STOP;
 while( !( hi2c1.Instance->CR1 & I2C_CR1_STOP )){;}
 }
}
 
void DMA_Init(void) {
 
    __HAL_RCC_DMA1_CLK_ENABLE();
    HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);
 
    dma_i2c1.Instance = DMA1_Stream6;
    dma_i2c1.Instance->CR = 0;
    dma_i2c1.Instance->CR |= DMA_CHANNEL_1;
    dma_i2c1.Instance->CR |= DMA_SxCR_TCIE;
    dma_i2c1.Instance->CR |= DMA_SxCR_DIR_0;
    dma_i2c1.Instance->CR |= DMA_SxCR_MINC;
 
}
 
uint32_t temp_cle = 0;
uint8_t  I2C_DMA_Transmit(DMA_HandleTypeDef *dma, I2C_HandleTypeDef *i2c, uint8_t Addr, uint8_t *pBuffer, uint16_t size)
{
 
    while ((i2c->Instance->SR2 & I2C_SR2_BUSY)) {;}
    i2c->Instance->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
    while (!(i2c->Instance->SR1 & I2C_SR1_SB)) {;}
    temp_cle = i2c->Instance->SR1;
    i2c->Instance->CR2 |= I2C_CR2_DMAEN;
    i2c->Instance->DR = Addr;
    while (!(i2c->Instance->SR1 & I2C_SR1_ADDR)) {;}
    temp_cle = i2c->Instance->SR1 | i2c->Instance->SR2;
 
    dma->Instance->PAR = (uint32_t) &(hi2c1.Instance->DR);
    dma->Instance->M0AR = (uint32_t) pBuffer;
    dma->Instance->NDTR = size + 1;
    dma->Instance->CR |= DMA_SxCR_EN;
return 0;
}
0
349 / 147 / 10
Регистрация: 19.07.2024
Сообщений: 825
10.10.2025, 20:42
Цитата Сообщение от VladimirU Посмотреть сообщение
Выкладываю для истории да и сам когда нибудь вернусь
C++
1
2
DMA1->HIFCR |= DMA_HIFCR_CTCIF6;
 while(( hi2c1.Instance->CR1 & I2C_SR1_BTF)){;}
Уже в первых строках вашего "творения" сразу несколько багов. И багов - типичных для кубокодеров, которые не читают мануалы.
Читаем мануал и пытаемся начать думать. Строки с багами выделил. Впрочем - там почти все строки с багами.

Цитата Сообщение от VladimirU Посмотреть сообщение
ой не знаю все куб обсерают ОХ как зря.
Вы сами привели пример говнокода, который создают фанаты Куба. Демонстрация "достоинств" Куба получилась - прям лучше некуда!

И так:
Цитата Сообщение от VladimirU Посмотреть сообщение
hi2c1.Instance->CR1 |= I2C_CR1_STOP;
 while( !( hi2c1.Instance->CR1 & I2C_CR1_STOP )){;}
мог написать только Кубокодер. И даже не икнулось, что ожидание СТОПа будет происходит в прерывании?? Типичный кубокодинг!
0
62 / 187 / 31
Регистрация: 14.02.2013
Сообщений: 1,717
10.10.2025, 20:55
jcxz, не надо ля ля это лишь пример вот и всё дальше конечно кому надо доработают. А если у меня МК только как драйвер для GLCD то вообще пофиг чего там в прерывании делается. Я вообще передачу данных не завязываю на прерывание только прим. Конечно ожидания конца потока DMA лучше вынести в суперлуп. Я потом допишу выложу сюда для смеха.
0
62 / 187 / 31
Регистрация: 14.02.2013
Сообщений: 1,717
12.10.2025, 14:59
jcxz, вообще бы хотелось все эти ожидания флагов осуществлять с пользой то есть пока ждём флаг выполняем в лупе другую часть кода.

Добавлено через 1 минуту
Цитата Сообщение от jcxz Посмотреть сообщение
Типичный кубокодинг!
И кстати это к кубокоденгу не имеет отношения это скорей моя безграмотность в создании алгоритмов для МК. Исправил
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
uint32_t temp_cle = 0;
uint8_t  I2C_DMA_Transmit(DMA_HandleTypeDef *dma, I2C_HandleTypeDef *i2c, uint8_t Addr, uint8_t *pBuffer, uint32_t size)
{
 
    while ((i2c->Instance->SR2 & I2C_SR2_BUSY)) {;}
    i2c->Instance->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
    while (!(i2c->Instance->SR1 & I2C_SR1_SB)) {;}
    temp_cle = i2c->Instance->SR1;
    i2c->Instance->CR2 |= I2C_CR2_DMAEN;
    i2c->Instance->DR = Addr;
    while (!(i2c->Instance->SR1 & I2C_SR1_ADDR)) {;}
    temp_cle = i2c->Instance->SR1 | i2c->Instance->SR2;
 
    dma->Instance->PAR = (uint32_t) &(hi2c1.Instance->DR);
    dma->Instance->M0AR = (uint32_t) pBuffer;
    dma->Instance->NDTR = (size + 1);
    dma->Instance->CR |= DMA_SxCR_EN;
 
    while(!(DMA1->HISR & DMA_HISR_TCIF6)){;}
    DMA1->HIFCR |= DMA_HIFCR_CTCIF6;
    while(( hi2c1.Instance->CR1 & I2C_SR1_BTF)){;}
    hi2c1.Instance->CR1 |= I2C_CR1_STOP;
    while( !( hi2c1.Instance->CR1 & I2C_CR1_STOP )){;}
 
return 0;
}
0
 Аватар для COKPOWEHEU
4149 / 2727 / 433
Регистрация: 09.09.2017
Сообщений: 12,086
12.10.2025, 15:13
Цитата Сообщение от VladimirU Посмотреть сообщение
вообще бы хотелось все эти ожидания флагов осуществлять с пользой то есть пока ждём флаг выполняем в лупе другую часть кода.
Ну так организуйте конечный автомат.
Скажем, в моей реализации на прерываниях, но без DMA, есть функция i2cm_isready, которая проверяет, закончилась ли уже предыдущая передача или, может, отвалилась по таймауту. Там же и ожидание сформировалось ли состояние STOP, на которое, к сожалению, нет прерывания.
0
349 / 147 / 10
Регистрация: 19.07.2024
Сообщений: 825
12.10.2025, 15:17
Цитата Сообщение от VladimirU Посмотреть сообщение
Исправил
Что именно "исправил"? Старые баги остались на месте. Но говнокод стал ещё более г*.
Зачем вообще тут прикостылено DMA если не используется его главное предназначение: разгрузка CPU?

Цитата Сообщение от VladimirU Посмотреть сообщение
И кстати это к кубокоденгу не имеет отношения
Имеет самое прямое. Так как главная ущербность кубокодинга состоит в том, что кубокодеры лепят свой код даже не заглядывая в документацию. Наугад. Что как раз и иллюстрируют ваши приведённые выше "коды".
0
62 / 187 / 31
Регистрация: 14.02.2013
Сообщений: 1,717
12.10.2025, 15:32
Цитата Сообщение от jcxz Посмотреть сообщение
Зачем вообще тут прикостылено DMA если вообще не используется его главное предназначение: разгрузка CPU?
Да я это понимаю и исправлю, мне был интересен как вообще работает DMA далее буду думать как всё это дело сделать более гибким.
Цитата Сообщение от jcxz Посмотреть сообщение
Наугад
Вообще то инициализацию DMA и порядок запуска писал по референт мануалу в месте i2c.

Добавлено через 2 минуты
COKPOWEHEU, выходит всё же придётся задействовать таймер для исправления ошибок в передачи по i2c но это самое оно гарантирует 100% выход из зависания i2c и последующей его переинициализации.
0
349 / 147 / 10
Регистрация: 19.07.2024
Сообщений: 825
12.10.2025, 15:41
Цитата Сообщение от VladimirU Посмотреть сообщение
Вообще то инициализацию DMA и порядок запуска писал по референт мануалу в месте i2c.
Если так, то почему я вижу такой "перл":
Цитата Сообщение от VladimirU Посмотреть сообщение
while(!(DMA1->HISR & DMA_HISR_TCIF6)){;}
Т.е. - если в процессе передачи возникнет ошибка, то ваш код просто повиснет в этом бесконечном цикле. Так как флаги ошибок вы обработать не удосужились.
Или наоборот - выход из этого цикла может произойти преждевременно. До завершения пересылки. Так как при инициализации передачи вы не удосужились почистить флаги DMA, и если от предыдущей передачи остался стоять флаг - цикл выше завершится преждевременно.
Нужно чистить все флажки прерываний данного потока после завершения передачи или/и (лучше) - перед каждым стартом новой DMA-передачи.

И куча других багов ещё в коде:
Цитата Сообщение от VladimirU Посмотреть сообщение
DMA1->HIFCR |= DMA_HIFCR_CTCIF6;
while(( hi2c1.Instance->CR1 & I2C_SR1_BTF)){;}
Как такое можно написать, глядя в документацию - не представляю.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
12.10.2025, 15:41

stm32f407+ADC+DMA. Проблема с DMA
Доброго дня! Новичок в stm, первый проект, начальные наброски, не понимаю,почему не работает эта...

STM32F4 I2C DMA CMSIS
Парни может кто писал под f4 скиньте рабочий код если не жалко

stm32 SPI+DMA или I2C внешнее АЦП
Есть у меня задача контролировать 3фазы линейно .Внутренний ацп не подходит наверное.Какое ацп...

передача данных USART + DMA и непонятные иероглифы
Всем привет! Есть проблема с передачей данных с МК на ПК через USORT + DMA. Ранее все работало...

stm32f4 SPI приём и передача данных по DMA
Посмотрел я примеры по SPI .Как правильно осуществить передачу данных и приём ?Особенно путаница с...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru