День добрый. Пока писали ТЗ к проекту, тестировал основные подходы, приемы решения проблем которые подымались в проекте. Последняя проблема была передача данных, она ко всему еще и трансформировалась по ходу написания ТЗ. Нюансы подымать не буду, мной уже подымалась данная тема и пользователь Unixon предложил на мой взгляд хорошее решение. Но так как в одном из проектов столкнулся с STM32F4Discovery и узнал про DMA решил делать проект на STM32F4Discovery. Мне показалось, такое решение более логичным. Задумка такая есть пакеты данных по 12 байт на отправку и получение. 2 отдельных UART, один на прием, другой на отправку через свои потоки DMA. Подробное описание DMA на русском в контексте STM32F4Discovery. https://www.youtube.com/playlist?list=PL8OgDYWys_b6XtOjCejd37aVv0ic24jqV Уроки 14-16. Среда Keil μVision. Основная библиотека STM32F4xx_DSP_StdPeriph_Lib_V1.4.0. Файл usart.c Код (Text): #include "usart.h" // Размер буфера для получения данных по DMA, через UART2 static const uint8_t bufferSizeDMAUSARTSend = 12; // Размер буфера для отправки данных по DMA, через UART3 static const uint8_t bufferSizeDMAUSARTReceive = 12; // Буфер для отправки данных по DMA, через UART2 char bufferDMAUSARTSend[bufferSizeDMAUSARTSend]; // Последний полученный Char char rxCharReceive; // Буфер для получения данных по DMA, через UART3 char bufferDMAUSARTReceive[bufferSizeDMAUSARTReceive]; // Индекс буфера для получения данных int16_t bufferDMAUSARTReceiveIndex = 0; // Статус полученных данных int8_t receiveDataStatus = 0; // Инициализация UART2 на отправку данных void USART2Init(void) { GPIO_InitTypeDef GPIO_Init_USART; USART_InitTypeDef USART_InitUser; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_Init_USART.GPIO_Pin = GPIO_Pin_2; GPIO_Init_USART.GPIO_Mode = GPIO_Mode_AF; GPIO_Init_USART.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init_USART.GPIO_OType = GPIO_OType_PP; GPIO_Init_USART.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOA, &GPIO_Init_USART); GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); USART_InitUser.USART_BaudRate = 115200; USART_InitUser.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitUser.USART_Mode = USART_Mode_Tx; USART_InitUser.USART_Parity = USART_Parity_No; USART_InitUser.USART_StopBits = USART_StopBits_1; USART_InitUser.USART_WordLength = USART_WordLength_8b; USART_Init(USART2, &USART_InitUser); USART_Cmd(USART2, ENABLE); } // Инициализация UART3 на получение данных void USART3Init(void) { GPIO_InitTypeDef GPIO_Init_USART; USART_InitTypeDef USART_InitUser; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_Init_USART.GPIO_Pin = GPIO_Pin_11; GPIO_Init_USART.GPIO_Mode = GPIO_Mode_AF; GPIO_Init_USART.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init_USART.GPIO_OType = GPIO_OType_PP; GPIO_Init_USART.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &GPIO_Init_USART); GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); USART_InitUser.USART_BaudRate=115200; USART_InitUser.USART_HardwareFlowControl=USART_HardwareFlowControl_None; USART_InitUser.USART_Mode=USART_Mode_Rx; USART_InitUser.USART_Parity=USART_Parity_No; USART_InitUser.USART_StopBits=USART_StopBits_1; USART_InitUser.USART_WordLength=USART_WordLength_8b; USART_Init(USART3, &USART_InitUser); //NVIC_EnableIRQ(USART3_IRQn); //USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); USART_Cmd(USART3, ENABLE); } // Инициализация DMA (DMA1_Channel_4_Stream6) для USRT2 на отправку данных void DMAUSART2Init(void) { DMA_InitTypeDef DMA_Init_USART; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); DMA_Init_USART.DMA_Channel = DMA_Channel_4; DMA_Init_USART.DMA_PeripheralBaseAddr = (uint32_t)&(USART2->DR); DMA_Init_USART.DMA_Memory0BaseAddr = (uint32_t)bufferDMAUSARTSend; DMA_Init_USART.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_Init_USART.DMA_BufferSize = bufferSizeDMAUSARTSend; DMA_Init_USART.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_Init_USART.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_Init_USART.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_Init_USART.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_Init_USART.DMA_Mode = DMA_Mode_Normal; DMA_Init_USART.DMA_Priority = DMA_Priority_Medium; DMA_Init_USART.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_Init_USART.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; DMA_Init_USART.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_Init_USART.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA1_Stream6, &DMA_Init_USART); USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE); NVIC_EnableIRQ(DMA1_Stream6_IRQn); DMA_ITConfig(DMA1_Stream6, DMA_IT_TC, ENABLE); } // Инициализация DMA (DMA1_Stream1) для UART3 на получение данных void DMAUSART3Init(void) { DMA_InitTypeDef DMA_Init_USART; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE); DMA_Init_USART.DMA_Channel = DMA_Channel_4; DMA_Init_USART.DMA_PeripheralBaseAddr = (uint32_t)&(USART3->DR); DMA_Init_USART.DMA_Memory0BaseAddr = (uint32_t)bufferDMAUSARTReceive; DMA_Init_USART.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_Init_USART.DMA_BufferSize = bufferSizeDMAUSARTReceive; DMA_Init_USART.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_Init_USART.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_Init_USART.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_Init_USART.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_Init_USART.DMA_Mode = DMA_Mode_Circular; DMA_Init_USART.DMA_Priority = DMA_Priority_High; DMA_Init_USART.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_Init_USART.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_Init_USART.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_Init_USART.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA1_Stream1, &DMA_Init_USART); USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE); NVIC_EnableIRQ(DMA1_Stream1_IRQn); DMA_ITConfig(DMA1_Stream1, DMA_IT_TC, ENABLE); DMA_Cmd(DMA1_Stream1, ENABLE); } // Функция отправки данных через DMA void SendDataToPC(char *SendData) { int8_t sizeSendData = strlen(SendData); if (sizeSendData == bufferSizeDMAUSARTSend) { memcpy(bufferDMAUSARTSend, SendData, bufferSizeDMAUSARTSend); DMA_Cmd(DMA1_Stream6, ENABLE); } } // Функция получения массива отправленных данных char * GetSendDataToPC() { return bufferDMAUSARTSend; } // Функция получения массива полученных данных char * GetReceiveDataToPC() { receiveDataStatus = 2; return bufferDMAUSARTReceive; } // Функция получения статуса полученных данных int8_t GetReceiveDataStatus() { return receiveDataStatus; } // Функция очистка массива полученных данных void ClearReceiveData() { memset(&bufferDMAUSARTReceive, '\0', sizeof(bufferDMAUSARTReceive)); receiveDataStatus = 0; } // Прерывание DMA1_Stream6 void DMA1_Stream6_IRQHandler(void) { if (DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) == SET) { DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6); } } // Прерывание DMA1_Stream1 void DMA1_Stream1_IRQHandler(void) { if (DMA_GetITStatus(DMA1_Stream1, DMA_IT_TCIF1) == SET) { DMA_ClearITPendingBit(DMA1_Stream1, DMA_IT_TCIF1); receiveDataStatus = 1; } } // Прерывание USART3 void USART3_IRQHandler(void) { if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET) { USART_ClearITPendingBit(USART3, USART_IT_RXNE); rxCharReceive = (char)USART_ReceiveData(USART3); if ((rxCharReceive == '\r') || (rxCharReceive == '\n')) { if (bufferDMAUSARTReceiveIndex != 0) { receiveDataStatus = 1; bufferDMAUSARTReceiveIndex = 0; } } else { bufferDMAUSARTReceive[bufferDMAUSARTReceiveIndex] = rxCharReceive; bufferDMAUSARTReceiveIndex++; } } } Файл usart.h Код (Text): #ifndef USART_H #define USART_H #include "stm32f4xx.h" #include <string.h> // Библиотека для работы со строкой // Инициализация USART2 на отправку данных void USART2Init(void); // Инициализация DMA (DMA1_Stream6) для USART2 на отправку данных void DMAUSART2Init(void); // Инициализация USART3 на получение данных void USART3Init(void); // Инициализация DMA (DMA1_Stream1) для USART3 на получение данных void DMAUSART3Init(void); // Функция отправки данных через DMA void SendDataToPC(char *SendData); // Функция получения массива отправленных данных char * GetSendDataToPC(void); // Функция получения массива полученных данных char * GetReceiveDataToPC(void); // Функция получения статуса полученных данных int8_t GetReceiveDataStatus(void); // Функция очистка массива полученных данных void ClearReceiveData(void); #endif
Файл main.с Код (Text): #include "main.h" int main(void) { // Обновляем, скрость работы процессора SystemCoreClockUpdate(); //SysTick_Config(SystemCoreClock/1000000); //LedOnBoard_Init(); //ButtonOnBoard_Init(); USART2Init(); DMAUSART2Init(); USART3Init(); DMAUSART3Init(); SendDataToPC("Hello World!"); while(1) { if (GetReceiveDataStatus() == 1) { char* bufferReceive = GetReceiveDataToPC(); ClearReceiveData(); } /*if (ButtonOnBoardRead() == 1) { LedOnBoard_On(BlueLedOnBoard); }*/ } } Идею с отправкой по UART + DMA позаимствована от сюда. С получением, пришлось поковыряться. Так же загружаю проект, в папке Arburg_Keli.rar. Из интересного там еще ADC+DMA. Если кому-то нужна отправка и получение UART без DMA. Получение, можно просто изменить код файла usart.c найти void USART3Init(void) и в этом методе раскомментировать строки Код (Text): //NVIC_EnableIRQ(USART3_IRQn); //USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); И в файле main.с найти int main(void) и в этом методе закомментировать Код (Text): DMAUSART3Init(); Отправка смотрите уроки, там есть и прием, но сделан упрощено, чтобы просто пояснить принцип работы. Возможно кому-то будет интересно клиентское приложение на C#, для чтения и отправки в Serial. Его можно использовать и для Ардуины и для STM32F4Discovery и т.д. Загружаю проект, в папке Default Serial Talk.rar (Visual Studio 2010 C#), как-то был найден мной на просторах инета. Файлы большие, не удалось загрузить здесь, поэтому на Yandex-е. https://yadi.sk/d/9tD4KUfscb2od https://yadi.sk/d/r3FuMxRRcb2tx P.S. Следующем шагом, была идея сделать UDP+DMA, но проект полностью заморожен. ТЗ полностью удалось закончить, начиная от гидравлических схем, схем шкафа электроники, схемой работы и т.д., на 2 различных ТПА. UPD. Готовые библиотеки для работы с USART, Но без DMA. http://stm32f4-discovery.com/2014/04/library-04-connect-stm32f429-discovery-to-computer-with-usart/ И Русского производства http://microtechnics.ru/biblioteka-dlya-raboty-s-usart-v-stm32/
Пакет 12 байт и буфер 12 байт - есть вероятность испортить пакет, если 2 пакета придут подряд. Обычно буфер делается вдвое больше и настраивается прерывание по середине буфера и по концу. Пока DMA пишет в первую половину буфера, вы обрабатываете вторую, потом наоборот. Я как раз ковыряю stm32f407 по работе, позже тоже попробую поиграться с DMA.
Возможно Вы правы. Просто пока еще не до конца, собрал все кучу и не проверял. Сейчас проект, мертв, просто упертый хотел разобраться до конца. Тоже надо было для работы, плата и возможности просто превосходные. Можно расширить буфер и добавить прерывание на получение половины пакета. Код (Text): DMA_ITConfig(DMA1_Stream1, DMA_IT_TC | DMA_IT_HT , ENABLE); Вместо Код (Text): DMA_ITConfig(DMA1_Stream1, DMA_IT_TC, ENABLE); Тогда надо добавить, в прерывание DMA1_Stream1_IRQHandler Код (Text): if (DMA_GetITStatus(DMA1_Stream1, DMA_IT_HTIF1)) { DMA_ClearITPendingBit(DMA1_Stream1, DMA_IT_HTIF1); } Вроде ни чего не напутал. Удачи в изучении, сам потихоньку ковыряю, хоть и нет проекта под нее. Покупал для мишени, но ума не хватило довести до конца.