DarkLight 0 April 7 Posted April 7 (edited) · Report post Опытные пользователи DMA, вот кусок программы не выходят данные по линии ТХ, что я делаю не так? где ошибка закралась? До использования DMA все работало. //************************************************************** void Init_USART1(void) { // Запускаем тактирование RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1); usart1_port.GPIO_Mode = GPIO_Mode_AF; usart1_port.GPIO_Pin = GPIO_Pin_6; usart1_port.GPIO_Speed = GPIO_Speed_50MHz; usart1_port.GPIO_OType = GPIO_OType_PP; usart1_port.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &usart1_port); usart1_port.GPIO_Mode = GPIO_Mode_AF; usart1_port.GPIO_Pin = GPIO_Pin_7; usart1_port.GPIO_Speed = GPIO_Speed_50MHz; usart1_port.GPIO_OType = GPIO_OType_PP; usart1_port.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &usart1_port); //------------------------------------------------------------- usart1_init.USART_BaudRate = 832000; usart1_init.USART_WordLength = USART_WordLength_8b; usart1_init.USART_StopBits = USART_StopBits_1; usart1_init.USART_Parity = USART_Parity_No; usart1_init.USART_HardwareFlowControl = USART_HardwareFlowControl_None; usart1_init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &usart1_init); //------------------------------------------------------------- memset(rx_buf,0,1000); memset(tx_buf,0,1000); rx_cnt = 0; tx_cnt = 1; uart1_reg = 0; //------------------------------------------------------------- Init_DMA_USART1(); DMA_IT_Init(); //------------------------------------------------------------- /* Enable USART1 */ USART_Cmd(USART1, ENABLE); //------------------------------------------------------------- //NVIC_EnableIRQ(USART1_IRQn); //USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // Включаем прерывание по окончанию передачи //USART_ITConfig(USART1, USART_IT_TC, ENABLE); } //************************************************************** void DMA_IT_Init(void) { DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE); // Прерывание по завершению передачи DMA_ITConfig(DMA2_Stream5, DMA_IT_TC, ENABLE); // Прерывание по завершению приема // В NVIC (в конце Init_USART1 или в отдельной функции) NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream5_IRQn; // Для приема NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn; // Для передачи NVIC_Init(&NVIC_InitStructure); } //************************************************************** void Init_DMA_USART1(void) { // Включаем тактирование DMA RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // ========== НАСТРОЙКА DMA ДЛЯ ПЕРЕДАЧИ (TX) ========== DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA2_Stream7); // Для USART1 TX обычно DMA2 Stream7 while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); // Ждем сброса DMA_InitStructure.DMA_Channel = DMA_Channel_4; // Канал DMA для USART1 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); // Адрес регистра данных USART1 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&tx_buf[0]; // Адрес нашего буфера DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Направление: из памяти в периферию DMA_InitStructure.DMA_BufferSize = 1000; // Размер буфера (1000 байт) DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Адрес периферии не меняем DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Адрес памяти увеличиваем DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_Init(DMA2_Stream7, &DMA_InitStructure); // Связываем DMA с USART1 для передачи USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // ========== НАСТРОЙКА DMA ДЛЯ ПРИЕМА (RX) ========== // Для приема используем другой канал (обычно DMA2 Stream5) DMA_DeInit(DMA2_Stream5); while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE); DMA_InitStructure.DMA_Channel = DMA_Channel_4; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&rx_buf[0]; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Направление: из периферии в память DMA_InitStructure.DMA_BufferSize = 1000; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Для приема "циклический" режим DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_Init(DMA2_Stream5, &DMA_InitStructure); DMA_Cmd(DMA2_Stream5, ENABLE); // Связываем DMA с USART1 для приема USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); } Каждые 20 мс вызываю такую вот функцию и на выходе ничего нет. Где я что забыл или делаю не так? //************************************************************** void USART1_Send_DMA(void) { // Останавливаем DMA, если он был активен DMA_Cmd(DMA2_Stream7, DISABLE); while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); // Ждем полной остановки // Устанавливаем счетчик байт DMA_SetCurrDataCounter(DMA2_Stream7, 1000); // Запускаем DMA DMA_Cmd(DMA2_Stream7, ENABLE); } Edited April 7 by DarkLight забыл слово Quote Share this post Link to post Share on other sites More sharing options...
tonyk_av 80 April 7 Posted April 7 · Report post 10 minutes ago, DarkLight said: что я делаю не так? где ошибка закралась? Прошу меня извинить, но можно я на вас проверю ответ ИИ? Quote Share this post Link to post Share on other sites More sharing options...
DarkLight 0 April 7 Posted April 7 · Report post 6 минут назад, tonyk_av сказал: Прошу меня извинить, но можно я на вас проверю ответ ИИ? Можно, а то мой ИИ ничего не говорит толкового, нехороший нечеловек Quote Share this post Link to post Share on other sites More sharing options...
dimka76 96 April 7 Posted April 7 · Report post On 4/7/2026 at 3:12 PM, tonyk_av said: Прошу меня извинить, но можно я на вас проверю ответ ИИ? Этот ответ является частным Вы можете получить доступ к этой странице, если владелец примет ваш запрос. Quote Share this post Link to post Share on other sites More sharing options...
danusha 1 April 7 Posted April 7 · Report post мой ии : Главная причина — ты не сбрасываешь флаги DMA перед повторным запуском потока. У STM32 DMA есть особенность: пока в регистре LISR/HISR висит флаг TCIF (Transfer Complete) от предыдущей передачи, новый запуск DMA_Cmd(..., ENABLE) фактически не стартует — поток сразу «считает» себя завершённым или просто игнорирует включение. Первый раз после ресета флагов нет, поэтому одна передача ещё могла бы пройти, но у тебя и она не идёт, потому что в Init_DMA_USART1 поток TX вообще ни разу не включается — там только USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE), а сам DMA2_Stream7 остаётся выключенным до первого вызова USART1_Send_DMA. Исправь функцию отправки так: void USART1_Send_DMA(void) { DMA_Cmd(DMA2_Stream7, DISABLE); while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); /* ОБЯЗАТЕЛЬНО: чистим все флаги Stream7 в HISR */ DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7 | DMA_FLAG_HTIF7 | DMA_FLAG_TEIF7 | DMA_FLAG_DMEIF7 | DMA_FLAG_FEIF7); /* На всякий случай чистим TC у USART (он взводится после прошлой передачи) */ USART_ClearFlag(USART1, USART_FLAG_TC); DMA_SetCurrDataCounter(DMA2_Stream7, 1000); DMA_Cmd(DMA2_Stream7, ENABLE); } И ещё несколько моментов, которые тебя укусят следом: Обработчик DMA2_Stream7_IRQHandler. Ты включил DMA_IT_TC и NVIC_EnableIRQ для Stream7/Stream5, но если в проекте нет соответствующих void DMA2_Stream7_IRQHandler(void) и void DMA2_Stream5_IRQHandler(void), при первом же прерывании улетишь в HardFault (точнее в дефолтный обработчик-ловушку). Внутри обработчика обязательно сбрасывай флаг: DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7); иначе зациклишься. GPIO PB6/PB7 для USART1 на F4 — это валидный альтернативный маппинг (есть ещё PA9/PA10), так что тут ок, но проверь, что у тебя именно F4 и что ноги физически разведены туда, куда смотришь осциллографом. На частой ошибке люди тыкают в PA9. tx_cnt = 1 — судя по имени, у тебя где-то логика по этому счётчику. С DMA она роли не играет, но убедись, что ничего параллельно не лезет в USART1->DR напрямую — это сломает поток DMA. DMA_Mode_Normal для TX + размер 1000 каждые 20 мс. На 832000 бод 1000 байт уходят примерно за 12 мс — впритык, но влезает. Если когда-нибудь захочешь чаще — получишь наложение, и без проверки DMA_GetCmdStatus/TC до старта новой передачи будет каша. Мелочь: на TX-ноге GPIO_PuPd_UP не нужен (линия и так в idle = 1 за счёт самого USART), на RX подтяжка вверх как раз полезна — у тебя обе одинаковые, это не ошибка, просто к сведению. Сначала добавь сброс флагов в USART1_Send_DMA — с вероятностью 95% TX оживёт сразу. Quote Share this post Link to post Share on other sites More sharing options...
DarkLight 0 April 7 Posted April 7 (edited) · Report post 43 минуты назад, danusha сказал: Обработчик DMA2_Stream7_IRQHandler. Ты включил DMA_IT_TC и NVIC_EnableIRQ для Stream7/Stream5, но если в проекте нет соответствующих void DMA2_Stream7_IRQHandler(void) и void DMA2_Stream5_IRQHandler(void), при первом же прерывании улетишь в HardFault (точнее в дефолтный обработчик-ловушку). Внутри обработчика обязательно сбрасывай флаг: DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7); иначе зациклишься. Процедуры есть, как раз там флаг DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7); делаю, они простые поэтому не стал сюда писать 43 минуты назад, danusha сказал: GPIO PB6/PB7 для USART1 на F4 — это валидный альтернативный маппинг (есть ещё PA9/PA10), так что тут ок, но проверь, что у тебя именно F4 и что ноги физически разведены туда, куда смотришь осциллографом. На частой ошибке люди тыкают в PA9. Нет тыкаю на разъем где должны быть данные, там удобнее чем на ножке смотреть, делал сначала по прерываниям ,но скорость большая решил разгрузить процессор маленько Спасибо за доработку сейчас исправлю и посмотрю что получится.... Edited April 7 by DarkLight Quote Share this post Link to post Share on other sites More sharing options...
DarkLight 0 April 8 Posted April 8 · Report post 15 часов назад, danusha сказал: мой ии : Главная причина — ты не сбрасываешь флаги DMA перед повторным запуском потока. У STM32 DMA есть особенность: пока в регистре LISR/HISR висит флаг TCIF (Transfer Complete) от предыдущей передачи, новый запуск DMA_Cmd(..., ENABLE) фактически не стартует — поток сразу «считает» себя завершённым или просто игнорирует включение. Первый раз после ресета флагов нет, поэтому одна передача ещё могла бы пройти, но у тебя и она не идёт, потому что в Init_DMA_USART1 поток TX вообще ни разу не включается — там только USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE), а сам DMA2_Stream7 остаётся выключенным до первого вызова USART1_Send_DMA. Исправь функцию отправки так: void USART1_Send_DMA(void) { DMA_Cmd(DMA2_Stream7, DISABLE); while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); /* ОБЯЗАТЕЛЬНО: чистим все флаги Stream7 в HISR */ DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7 | DMA_FLAG_HTIF7 | DMA_FLAG_TEIF7 | DMA_FLAG_DMEIF7 | DMA_FLAG_FEIF7); /* На всякий случай чистим TC у USART (он взводится после прошлой передачи) */ USART_ClearFlag(USART1, USART_FLAG_TC); DMA_SetCurrDataCounter(DMA2_Stream7, 1000); DMA_Cmd(DMA2_Stream7, ENABLE); } И ещё несколько моментов, которые тебя укусят следом: Обработчик DMA2_Stream7_IRQHandler. Ты включил DMA_IT_TC и NVIC_EnableIRQ для Stream7/Stream5, но если в проекте нет соответствующих void DMA2_Stream7_IRQHandler(void) и void DMA2_Stream5_IRQHandler(void), при первом же прерывании улетишь в HardFault (точнее в дефолтный обработчик-ловушку). Внутри обработчика обязательно сбрасывай флаг: DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7); иначе зациклишься. GPIO PB6/PB7 для USART1 на F4 — это валидный альтернативный маппинг (есть ещё PA9/PA10), так что тут ок, но проверь, что у тебя именно F4 и что ноги физически разведены туда, куда смотришь осциллографом. На частой ошибке люди тыкают в PA9. tx_cnt = 1 — судя по имени, у тебя где-то логика по этому счётчику. С DMA она роли не играет, но убедись, что ничего параллельно не лезет в USART1->DR напрямую — это сломает поток DMA. DMA_Mode_Normal для TX + размер 1000 каждые 20 мс. На 832000 бод 1000 байт уходят примерно за 12 мс — впритык, но влезает. Если когда-нибудь захочешь чаще — получишь наложение, и без проверки DMA_GetCmdStatus/TC до старта новой передачи будет каша. Мелочь: на TX-ноге GPIO_PuPd_UP не нужен (линия и так в idle = 1 за счёт самого USART), на RX подтяжка вверх как раз полезна — у тебя обе одинаковые, это не ошибка, просто к сведению. Сначала добавь сброс флагов в USART1_Send_DMA — с вероятностью 95% TX оживёт сразу. Не помогло к сожалению, тишина на ножке.... не могу понять почему вроде все есть же.... может нужна определенная последовательность настройки? Quote Share this post Link to post Share on other sites More sharing options...
DarkLight 0 April 8 Posted April 8 · Report post Теперь код выглядит так и все равно не работает. //************************************************************** void Init_USART1(void) { // Запускаем тактирование RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //------------------------------------------------------------- GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1); usart1_port.GPIO_Mode = GPIO_Mode_AF; usart1_port.GPIO_Pin = GPIO_Pin_6; usart1_port.GPIO_Speed = GPIO_Speed_50MHz; usart1_port.GPIO_OType = GPIO_OType_PP; usart1_port.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &usart1_port); usart1_port.GPIO_Mode = GPIO_Mode_AF; usart1_port.GPIO_Pin = GPIO_Pin_7; usart1_port.GPIO_Speed = GPIO_Speed_50MHz; usart1_port.GPIO_OType = GPIO_OType_PP; usart1_port.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &usart1_port); //------------------------------------------------------------- usart1_init.USART_BaudRate = 832000; usart1_init.USART_WordLength = USART_WordLength_8b; usart1_init.USART_StopBits = USART_StopBits_1; usart1_init.USART_Parity = USART_Parity_No; usart1_init.USART_HardwareFlowControl = USART_HardwareFlowControl_None; usart1_init.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, &usart1_init); //------------------------------------------------------------- memset(rx_buf,0,1000); memset(tx_buf,0,1000); memset(cmd_buf,0,356); memset(sound_buf,0,640); memset(mic_buf,0,640); rx_cnt = 0; tx_cnt = 1000; cmd_cnt = 0; uart1_reg = 0; //------------------------------------------------------------- Init_DMA_USART1(); DMA_IT_Init(); //------------------------------------------------------------- /* Enable USART1 */ USART_Cmd(USART1, ENABLE); //------------------------------------------------------------- } //************************************************************** void DMA2_Stream7_IRQHandler(void) { if(DMA_GetFlagStatus(DMA2_Stream7, DMA_FLAG_TCIF7)) { DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7); } } //************************************************************** void DMA2_Stream5_IRQHandler(void) { if(DMA_GetFlagStatus(DMA2_Stream5, DMA_FLAG_TCIF5)) { DMA_ClearITPendingBit(DMA2_Stream5, DMA_IT_TCIF5); // Здесь 1000 байт успешно приняты и лежат в USART1_Rx_Buffer uart1_reg |= uart1_rx; } } //************************************************************** void DMA_IT_Init(void) { DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE); // Прерывание по завершению передачи DMA_ITConfig(DMA2_Stream5, DMA_IT_TC, ENABLE); // Прерывание по завершению приема NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream5_IRQn; // Для приема NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn; // Для передачи NVIC_Init(&NVIC_InitStructure); } //************************************************************** void Init_DMA_USART1(void) { // Включаем тактирование DMA (для STM32F4 это обычно AHB1) RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); // ========== НАСТРОЙКА DMA ДЛЯ ПЕРЕДАЧИ (TX) ========== DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA2_Stream7); // Для USART1 TX обычно DMA2 Stream7 while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); // Ждем сброса DMA_InitStructure.DMA_Channel = DMA_Channel_4; // Канал DMA для USART1 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); // Адрес регистра данных USART1 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&tx_buf[0]; // Адрес нашего буфера DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Направление: из памяти в периферию DMA_InitStructure.DMA_BufferSize = 1000; // Размер буфера (1000 байт) DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Адрес периферии не меняем DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Адрес памяти увеличиваем (берем следующий байт) DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // Режим "один раз" (передал 1000 байт и остановился) DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_Init(DMA2_Stream7, &DMA_InitStructure); DMA_Cmd(DMA2_Stream7, ENABLE); // Связываем DMA с USART1 для передачи USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // ========== НАСТРОЙКА DMA ДЛЯ ПРИЕМА (RX) ========== // Для приема используем другой канал (обычно DMA2 Stream5) DMA_DeInit(DMA2_Stream5); while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE); DMA_InitStructure.DMA_Channel = DMA_Channel_4; // Канал тот же (DMA_Channel_4) DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&rx_buf[0]; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Направление: из периферии в память DMA_InitStructure.DMA_BufferSize = 1000; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Для приема лучше "циклический" режим DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_Init(DMA2_Stream5, &DMA_InitStructure); DMA_Cmd(DMA2_Stream5, ENABLE); // Связываем DMA с USART1 для приема USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); } Процедура запуска //************************************************************** // Запуск отправки 1000 байт через DMA void USART1_Send_DMA(void) { // Останавливаем DMA, если он был активен DMA_Cmd(DMA2_Stream7, DISABLE); while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); // Ждем полной остановки // Устанавливаем счетчик байт (на случай, если он изменился) DMA_SetCurrDataCounter(DMA2_Stream7, 1000); // Очищаем флаги, если нужно DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7 | DMA_FLAG_HTIF7 | DMA_FLAG_TEIF7 | DMA_FLAG_DMEIF7 | DMA_FLAG_FEIF7); // Запускаем DMA DMA_Cmd(DMA2_Stream7, ENABLE); } Будет удобнее, если кто-то еще захочет помучать ИИ. Quote Share this post Link to post Share on other sites More sharing options...
Patifon_Kakao 1 April 8 Posted April 8 · Report post Мой ИИ говорит: 1. CCM RAM и DMA У F407 есть CCM (ядровая память). DMA из CCM не читает и туда не пишет. Если tx_buf / rx_buf попали в секцию .ccmram или похожую в линкере — по TX может быть полная тишина. Проверьте в .map: адрес буфера должен быть в обычной SRAM (не в CCM). При необходимости явно оставьте буферы в обычной памяти (без размещения в CCM). 2. Не включать Stream7 в Init После DMA_Init для TX не делайте DMA_Cmd(DMA2_Stream7, ENABLE) в инициализации. Поток включайте только в USART1_Send_DMA, когда tx_buf уже заполнен. Иначе легко получить гонку с первым «пустым» проходом и путаницу со счётчиком. 3. Порядок Имеет смысл: USART_Init → настройка DMA (потоки выкл.) → USART_Cmd(USART1, ENABLE) → USART_DMACmd(..., Tx) → первый DMA_Cmd(Stream7, ENABLE) уже из процедуры отправки. Итого для F407: сначала исключите CCM для tx_buf, затем поправьте включение только Stream7 при отправке и порядок USART_Cmd / USART_DMACmd. Quote Share this post Link to post Share on other sites More sharing options...
DarkLight 0 April 8 Posted April 8 · Report post 30 минут назад, Patifon_Kakao сказал: Не включать Stream7 в Init После DMA_Init для TX не делайте DMA_Cmd(DMA2_Stream7, ENABLE) в инициализации. Поток включайте только в USART1_Send_DMA, когда tx_buf уже заполнен. Иначе легко получить гонку с первым «пустым» проходом и путаницу со счётчиком. Да уже пробовал так и так.... первый код как раз который выложен был сделан именно так как Вы пишите.... пробую разные варианты, хоть как-нибудь запустить Quote Share this post Link to post Share on other sites More sharing options...
tonyk_av 80 April 9 Posted April 9 · Report post On 4/7/2026 at 5:19 PM, DarkLight said: Можно Я сам ХАЛом не пользуюсь, но подобрать ИИ, который даёт более-менее адекватные ответы, хочется. Ниже ответ www.perplexity.ai Spoiler У вас почти всё правильно, но прямая передача по DMA из tx_buf не запускается, потому что вы не повторно инициализируете/настраиваете DMA‑канал перед каждым USART1_Send_DMA. Ниже — по шагам, где именно “закопалась” ошибка и как исправить. 1. Основная ошибка: DMA_SetCurrDataCounter без DMA_Init Вы в USART1_Send_DMA только: DMA_SetCurrDataCounter(DMA2_Stream7, 1000); DMA_Cmd(DMA2_Stream7, ENABLE); Это недостаточно. DMA‑поток не сбрасил: CMEN (флаг завершения), не перечитал DMA_InitStructure, буфер tx_buf уже был передан один раз, и простое изменение счетчика не перезапускает полноценный цикл. Что нужно: перед DMA_Cmd(ENABLE) заново вызвать DMA_Init (или по меньшей мере правильно настроить буфер). 2. Правильный вариант USART1_Send_DMA void USART1_Send_DMA(void) { // Останавливаем DMA DMA_Cmd(DMA2_Stream7, DISABLE); while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); // Обязательно: сначала НАСТРОЙКА, потом ENABLE DMA_SetCurrDataCounter(DMA2_Stream7, tx_cnt); // реально передаём tx_cnt, не 1000 DMA_Cmd(DMA2_Stream7, ENABLE); // теперь DMA запустится } Но и этого мало, если вы не следите за статусами DMA: Если поток уже был в Complete, DMA после DISABLE/ENABLE не перезапустится, пока вы не сбросите флаги: DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7); и/или не проверяете, что DMA_GetCmdStatus(DMA2_Stream7) == DISABLE и флаги завершения сброшены. 3. Самое важное: перед каждым вызовом DMA нужно убедиться, что Буфер tx_buf заполнен тем, что есть смысл отправлять (tx_cnt реальный размер, а не 1000). DMA‑канал не находится в “заблокированном” по завершению состоянии. Пример минимального исправления: void USART1_Send_DMA(void) { // 1. Ожидаем, что DMA завершил предыдущую передачу while (DMA_GetCmdStatus(DMA2_Stream7) != DISABLE); // 2. Сбрасываем флаг завершения (если он был установлен) DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7); // 3. Устанавливаем реальный размер буфера DMA_SetCurrDataCounter(DMA2_Stream7, tx_cnt); // 4. Включаем DMA DMA_Cmd(DMA2_Stream7, ENABLE); } 4. Что ещё может “подрезать” TX USART1 TX не включён как DMA‑источник У вас есть: USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);Это ок. Но если вы где‑то включали Буфер tx_buf пуст В Init_USART1 вы делаете: memset(tx_buf,0,1000); tx_cnt = 1; Это значит: DMA будет передавать 1 байт, который равен 0x00. Если на другом конце стоит приёмник, который не реагирует на 0x00, то “ничего не видно”. Проверьте, что: tx_buf[0] реально содержит что‑то видимое (например 0x41 → 'A'). tx_cnt корректно устанавливается в USART1_Send_DMA перед вызовом. 5. Проверьте тактирование и альтернативные функции Убедитесь, что: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); вызываются до инициализации USART и DMA. Если вы где‑то включаете/выключаете тактирование, это сразу “ломает” DMA. Убедитесь, что: GPIOB тактируется: RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1); для USART1_TX (обычно PB6 или PB7 — зависит от чипа, но у вас PB6 и PB7 — это проблема, но оставим на потом). 6. Возможная проблема с пинами TX Вы настраиваете: GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1); GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1); Но: USART1_TX у STM32F4 обычно PB6 или PA9, а USART1_RX — PB7 или PA10. Если вы на PB6 повесили TX, а на PB7 также TX (или перепутано RX/TX), то DMA будет “передавать” в правильный USART1->DR, но сигнал не пойдёт по правильному пину. Проверьте даташит/кубу студию: Реальный пин USART1 TX у вашего чипа. Исправьте GPIO_PinSource* под него, например: GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1); // PB6 → TX GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1); // PB7 → RX 7. Что проверить шаг за шагом Убедитесь, что tx_buf[0] = 0x41; и tx_cnt = 1; перед USART1_Send_DMA(). В USART1_Send_DMA: DMA_SetCurrDataCounter(DMA2_Stream7, tx_cnt); DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7); DMA_Cmd(DMA2_Stream7, ENABLE); Включите на другом конце (PC/анализатор) отображение 0x41 (A). Если по‑прежнему ничего нет — замените пока DMA на обычный USART_SendData() и проверьте, что по линии TX что‑то уже идёт. Если без DMA всё работает — ошибка именно в повторном запуске DMA‑потока. Если скинете: кусок кода, где вы формируете tx_buf и вызываете USART1_Send_DMA (например, из таймера каждые 20 мс), и модель чипа (например, STM32F407), я подправлю вам конкретную функцию USART1_Send_DMA уже “под этот случай” так, чтобы TX сразу заработал. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 335 April 9 Posted April 9 · Report post Собсна, дожили. 1 Quote Share this post Link to post Share on other sites More sharing options...
dimka76 96 April 9 Posted April 9 · Report post 9 minutes ago, Arlleex said: Собсна, дожили. 100% Quote Share this post Link to post Share on other sites More sharing options...
haker_fox 162 April 9 Posted April 9 · Report post 10 minutes ago, Arlleex said: Собсна, дожили. В контексте того, что зачем задываться глубже того, что тебе достаточно. Ну устраивает коллег ответ ИИ, и хорошо. Сорри за ОФФ. Quote Share this post Link to post Share on other sites More sharing options...
tonyk_av 80 April 9 Posted April 9 · Report post 48 minutes ago, Arlleex said: Собсна, дожили. 39 minutes ago, dimka76 said: 100% А вы сами попробуйте. Я попробовал. Прошерстить Инет и найти ссылки на нужные доки ИИ может очень хорошо. Показать каркас какой-то типовой функции, сопроводив комментариями тоже делает вполне не плохо. Объяснить, что не нравится компилятору и показать в программе место, где нужно внести исправления у ИИ тоже хорошо получается. Проанализировать лог программы и её текст, чтобы объяснить, почему реальность не совпала с ожиданием и дать список необходимых изменений в программе у него тоже получается вполне успешно. То есть ИИ вполне может взять на себя часть программистской рутины. Так зачем после этого бомбить чаты-форумы вопросами, которые вполне можно решить с помощью ИИ (это не претензия ТСу)? Я также увидел, что ИИ иной раз не видит то, что легко видит человек, поэтому слепо верить ему нельзя, хотя переформулирование вопроса может помочь ИИ дать правильный ответ. В общем, там, где нужно тупо просеять много букв-цифр и выцепить нужное, ИИ может сильно помочь. Ещё удобно, что общение идёт на естественном языке. Quote Share this post Link to post Share on other sites More sharing options...