2015-08-07 07:53 PM
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
2015-08-07 08:23 PM
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 family2015-08-07 09:01 PM
Hi clive,
I post the incorrect code of DMA tx IRQ of USART2, which shoud be DMA1_Stream6 for USART2 tx done.2015-08-07 09:03 PM
Yes, I'm using STM32F407.
2015-08-07 09:45 PM
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?2015-08-08 01:33 AM
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
}
}