cancel
Showing results for 
Search instead for 
Did you mean: 

how to override printf to USART transfer with DMA

hxf0223
Associate II
Posted on August 08, 2015 at 04:53

Hello,

I want to use USART2 of STM32 as debug output of application, so i overload printf as below:


#pragma import(__use_no_semihosting)

struct
__FILE {

int
handle;

} __stdout;


void
_sys_exit(
int
x) { x = x; }


int
fputc
( 
int
ch, 
FILE
*f ) 
// overload fputc

{

while
( (USART2->SR&0X40) == 0 );

USART2->DR = (u8)ch;

return
ch;

}


int
printf
( 
const
char
* format, ... )

{

int
rv;

va_list
arg;


while
( flag_tx_usart2_dma_busy ); 
// wait for DMA1_Stream6 IRQ finish if not

flag_tx_usart2_dma_busy = 1;


va_start
(arg, format);

rv = vsnprintf((
char
*)usart2_dma_tx_buf, USART2_DMA_TX_BUF_SIZE, format, arg);

va_end
(arg);


DMA_SetCurrDataCounter(DMA1_Stream6, rv); 
// set data number to send

DMA_Cmd(DMA1_Stream6, ENABLE); 
// start DMA -> USART -> PC

return
rv;

}

The IRQ of DMA TX:

1.
void
DMA1_Stream6_IRQHandler(
void
)
2.
{
3.
if
( DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) ) {
4.
DMA_Cmd(DMA1_Stream6, DISABLE); 
// disable DMA
5.
DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6); 
// Clear DMA Stream Transfer Complete interrupt pending bit
6.
flag_tx_usart2_dma_busy = 0; 
// clear busy flag
7.
}
8.
}

at last i call printf in USART1 IRQ, and found it not called. that's to say, the overload not functional. I do not know why? #stm32-printf-overload
5 REPLIES 5
Posted on August 08, 2015 at 05:23

So is it stream 6 or 7? Pick one and apply consistently.

Which STM32 part, it's a bit ambiguous.

I'm thinking Stream 6 for the STM32F4 family

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
hxf0223
Associate II
Posted on August 08, 2015 at 06:01

Hi clive,

I post the incorrect code of DMA tx IRQ of USART2, which shoud be DMA1_Stream6 for USART2 tx done.

hxf0223
Associate II
Posted on August 08, 2015 at 06:03

Yes, I'm using STM32F407.

Posted on August 08, 2015 at 06:45

So what's the failure mechanism? It works once an stops, doesn't send anything?

Is the flag volatile?

I would probably clear the TC flags before disabling the DMA.

I know I can send multiple strings by reinitializing the DMA and each TC.

Can you post a sufficiently complete example that it can be built and tested?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
hxf0223
Associate II
Posted on August 08, 2015 at 10:33

Hi,clive,

forgive for my bad description. what i mean is that the when call printf like in main(), the PC can receive the whole message, but the overrided printf defined below (2) not called. 1, data definition for USART2+DMA TX:

#define USART2_DMA_TX_BUF_SIZE 256
static
uint8_t usart2_dma_tx_buf[USART2_DMA_TX_BUF_SIZE];
static
volatile
uint8_t flag_tx_usart2_dma_busy = 0;

2, printf override:

#if 1
#pragma import(__use_no_semihosting)
struct
__FILE {
int
handle;
} __stdout;
void
_sys_exit(
int
x) { x = x; }
int
fputc
( 
int
ch, 
FILE
*f )
{
while
( (USART2->SR & 0x80) == 0 ); 
// 80 = TXE, 40 = TC
USART2->DR = c;
return
1;
}
int
printf
( 
const
char
* format, ... )
{
int
rv;
va_list
arg;
while
( flag_tx_usart2_dma_busy ); 
// wait for DMA TX IRQ finish

flag_tx_usart2_dma_busy = 1;
va_start
(arg, format);
rv = vsnprintf((
char
*)usart2_dma_tx_buf, USART2_DMA_TX_BUF_SIZE, format, arg);
va_end
(arg);
DMA_SetCurrDataCounter(DMA1_Stream6, rv);


DMA_Cmd(DMA1_Stream6, ENABLE);
return
rv;
}
#endif

3, USART2 and DMA init:

static
void
imp_usart2_dma_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); 
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//////////////////////////////////////////////////////////////////////////
// USART2 configure

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(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE); 
USART_ClearFlag(USART2, USART_FLAG_TC);
//////////////////////////////////////////////////////////////////////////
// DMA TX configure

// DMA IRQ configure

NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// DMA stream configure

DMA_DeInit(DMA1_Stream6);
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->DR); 


DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)usart2_dma_tx_buf;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_BufferSize = USART2_DMA_TX_BUF_SIZE;
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_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_Init(DMA1_Stream6, &DMA_InitStructure);
DMA_ITConfig(DMA1_Stream6, DMA_IT_TC, ENABLE);
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE); 
}

4, DMA1_Stream6 IRQ:

void
DMA1_Stream6_IRQHandler(
void
)
{
if
( DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) ) {
DMA_Cmd(DMA1_Stream6, DISABLE); 
// close DMA
DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6); 
// Clear DMA Stream Transfer Complete interrupt pending bit
flag_tx_usart2_dma_busy = 0; 
// clear busy flag when DMA TX done

}
}