Questions regarding implementing a UART_DMA Receiver.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-03-03 11:35 AM
Hi ST Forum,
I want to implement a DMA RS232 device (with a MAX232 transceiver), where if the master sends a certain message (e.g. 0x01), then the STM32 will send back a certain message (e.g. 0x02). I got the DMA Transmit part working, but I'm wondering how to:1. Implement the DMA_Rx section2. Control the timing of DMA_Tx based on what is received DMA_RxIs this even possible?My DMA_Tx (working) is follows, any suggestion how to progress is strongly appreciated./* * PC6 USART6_TX * PC7 UART6_RX * Rate = 115.2k * Tested working 03/03/15 */#include ''stm32f4xx_dma.h''#include ''stm32f4xx_gpio.h''#include ''stm32f4xx_usart.h''#include ''stm32f4xx_rcc.h''#include ''misc.h''#include ''semihosting.h''#define UART_SPEED 115200 //defines 9600//char Buffer[] = ''The quick brown fox jumps over the lazy dog\r\n'';char Buffer[] = {0x01,0x02,0x03,0x04};void RCC_Configuration(void){ /* UART4 clock enable */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE); /* GPIOC clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); /* DMA1 clock enable */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);}void GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // PC.10 UART4_TX, potential clash SCLK CS43L22 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); /* Connect USART pins to AF */ GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6); GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_USART6);}void UART4_Configuration(void){ USART_InitTypeDef USART_InitStructure; /* USARTx configured as follow: - BaudRate = 9600 baud, can be up to 115200 - Word Length = 8 Bits - One Stop Bit - No parity - Hardware flow control disabled (RTS and CTS signals) - Receive and transmit enabled*/ USART_InitStructure.USART_BaudRate = UART_SPEED; //9600 baud USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART6, &USART_InitStructure); USART_Cmd(USART6, ENABLE);}void DMA_Configuration(void){ DMA_InitTypeDef DMA_InitStructure; DMA_DeInit(DMA2_Stream6); DMA_InitStructure.DMA_Channel = DMA_Channel_5; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Transmit DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer; DMA_InitStructure.DMA_BufferSize = (uint16_t)sizeof(Buffer); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART6->DR; 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_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream6, &DMA_InitStructure); USART_DMACmd(USART6, USART_DMAReq_Tx, ENABLE); /* Enable the USART Tx DMA request */ DMA_ITConfig(DMA2_Stream6, DMA_IT_TC, ENABLE); /* Enable DMA Stream Transfer Complete interrupt */ DMA_Cmd(DMA2_Stream6, ENABLE); /* Enable the DMA Tx Stream */}void DMA2_Stream6_IRQHandler(void){ /* Test on DMA Stream Transfer Complete interrupt */ if (DMA_GetITStatus(DMA2_Stream6, DMA_IT_TCIF4)) { /* Clear DMA Stream Transfer Complete interrupt pending bit */ DMA_ClearITPendingBit(DMA2_Stream6, DMA_IT_TCIF4); }}void NVIC_Configuration(void){ NVIC_InitTypeDef NVIC_InitStructure; /* Configure the Priority Group to 2 bits */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* Enable the UART4 RX DMA Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream6_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);}int main(void){ RCC_Configuration(); NVIC_Configuration(); GPIO_Configuration(); UART4_Configuration(); DMA_Configuration(); while(1) { }}- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-03-03 12:36 PM
DMA_IT_TCIF4 should be DMA_IT_TCIF6 for Stream 6
So basically a port from a UART4 DMA TX example to USART6 TX Are you sure there are any benefits here to using DMA RX for this? Surely the simplest solution is to have a state machine, service the USART RXNE, and identify the input character(s), and queue up DMA TX response(s).Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-03-03 1:00 PM
Thanks clive!
I almost forgot. So basically, Initiate RXNE Interrupt. During interrupt, check received data. But, how would I control when to send DMA_TX output using Rx received data? (Right now I only know how to send in a continuous loop, or send one singular right after startup)Much appreciated.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-03-03 1:42 PM
You'd want to queue up output buffers, and light off new ''Normal'' mode DMA transfers in the TC interrupt as the prior one completes.
I build a multi-string USART6 DMA example in this other thread./public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/DMA%20Memory%20To%20UART5&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=4051
// STM32 USART6 DMA TX/RX (Tx PC.6, Rx PC.7) STM32F4 Discovery - sourcer32@gmail.com
#include ''stm32f4_discovery.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
/* --------------------------- System Clocks Configuration -----------------*/
/* USART6 clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);
/* GPIOC clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
/* DMA2 clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*-------------------------- GPIO Configuration ----------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // PC.6 USART6_TX, PC.7 USART6_RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Connect USART pins to AF */
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_USART6);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_USART6);
}
/**************************************************************************************/
void USART6_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
/* USARTx configuration ------------------------------------------------------*/
/* USARTx configured as follow:
- BaudRate = 115200 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
*/
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART6, &USART_InitStructure);
USART_Cmd(USART6, ENABLE);
}
/**************************************************************************************/
// Output as a loop, received data overwrites, and subsequently outputs during next cycle
char Buffer[] = ''The quick brown fox jumps over the lazy dog
'';
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
// USART6_TX DMA Channel 5, DMA2, Stream7 (alt Stream6 potential clash SDIO)
DMA_DeInit(DMA2_Stream7);
DMA_InitStructure.DMA_Channel = DMA_Channel_5;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Transmit
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer;
DMA_InitStructure.DMA_BufferSize = (uint16_t)sizeof(Buffer) - 1;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART6->DR;
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_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream7, &DMA_InitStructure);
/* Enable the USART Tx DMA request */
USART_DMACmd(USART6, USART_DMAReq_Tx, ENABLE);
/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, ENABLE);
/* Enable the DMA TX Stream */
DMA_Cmd(DMA2_Stream7, ENABLE);
// USART6_RX DMA Channel 5, DMA2, Stream1 (alt Stream2)
DMA_DeInit(DMA2_Stream1);
DMA_InitStructure.DMA_Channel = DMA_Channel_5;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Receive
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer;
DMA_InitStructure.DMA_BufferSize = (uint16_t)sizeof(Buffer) - 1;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART6->DR;
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_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA2_Stream1, &DMA_InitStructure);
/* Enable the USART Rx DMA request */
USART_DMACmd(USART6, USART_DMAReq_Rx, ENABLE);
/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream1, DMA_IT_TC, ENABLE);
/* Enable the DMA RX Stream */
DMA_Cmd(DMA2_Stream1, ENABLE);
}
/**************************************************************************************/
void DMA2_Stream7_IRQHandler(void) // USART6_TX
{
/* Test on DMA Stream Transfer Complete interrupt */
if (DMA_GetITStatus(DMA2_Stream7, DMA_IT_TCIF7))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7);
}
}
/**************************************************************************************/
void DMA2_Stream1_IRQHandler(void) // USART6_RX
{
/* Test on DMA Stream Transfer Complete interrupt */
if (DMA_GetITStatus(DMA2_Stream1, DMA_IT_TCIF1))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA2_Stream1, DMA_IT_TCIF1);
}
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the Priority Group to 2 bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* Enable the USART6 TX DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable the USART6 RX DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
USART6_Configuration();
DMA_Configuration();
while(1); // Don't want to exit
}
/**************************************************************************************/
Up vote any posts that you find helpful, it shows what's working..
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-03-25 1:48 PM
Hey Clive,
Thanks so much for the response. I currently have the RXNE interrupt, and data reading also setup, attached follows. But how exactly would you light off new DMA ''normal'' transfer? Is it by DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7);? Clearing transfer complete interrupt and thus another normal mode starts?Appreciated.Attached RXNE interrupt code:void USART6_IRQHandler(void){ // Ignore framing/parity/error issues for now if(USART_GetITStatus(USART6, USART_IT_RXNE) == SET) { if(USART_ReceiveData(USART6)==0xA1) { // uint16_t temp = UART4->DR; // Or USART_ReceiveData(UART4); DMA_ClearITPendingBit(DMA2_Stream7, DMA_IT_TCIF7); GPIOD->BSRRL = GPIO_Pin_12; //debugging only } }}- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2015-03-25 2:29 PM
I currently have the RXNE interrupt, and data reading also setup, attached follows. But how exactly would you light off new DMA ''normal'' transfer?
The cited multi-string example should illustrate how to light off a new DMA transaction after the previous one ended. You might want to flag when it goes idle, so as to know when to start again.Up vote any posts that you find helpful, it shows what's working..
