STM32F2 USART1/6 DMA sends one string only
Obviously I'm missing something here, but at present I can't see what. I'm hoping someone can see the oversight.
I'm using all six USART/UARTs with DMA Tx on an STM32F205. I have a generic initialisation process for them, first setting up the device specific data and calling the relevant routines. Ditto the load-DMA actions.
USARTs 2 an3, and UARTs 4 & 5 all work as expected.
USARTs 1 and 6 send the first string I load to the DMA, but never send any others. The Baud rates are correct, so I think it's not a PCLK issue, which is one obvious difference between USART1&6 and the others. The other obvious difference is that they're on DMA2, where the others are on DMA1, but the first string goes, so I'm not doing anything too obviously wrong.
What happens is that when I load the first string, the DMA data is set up, and on DMA enable, NDTR goes to zero as expected as the data is sent. However when I load subsequent strings, NDTR does not change, no data is sent.
In both cases, I first check if the DMA is ready:
if( DISABLE == DMA_GetCmdStatus( pDevData->pTxDMAy_Streamx ) ) // If the DMA is ready
{....
It is (despite on third and later checks, NDTR is non-zero), so I clear all related Tx flags, load the string and length to the Init structure, Init and enable the DMA. And nothing happens.
If I compare the settings in USART1 and USART3 DMA stream registers, they're identical.
If I compare the settings in the USART1 and USART3 registers, they're identical apart from the Baud rate settings (because of PCLK2).
A couple of code clips below, main file attached.
------------------------------------------------------------
#ifdef USE_USART1
/* Enable the USARTx Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_Init(&NVIC_InitStructure);
/* Enable USART clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
/* Connect USART pins to AF7 */
// ( done by mx_pinout_config() )
// Enable the USART OverSampling by 8 for fast data rates
// USART_OverSampling8Cmd(USART1, ENABLE);
usart1_device_data.pUSART = USART1; // Pointer to physical USART or UART
usart1_device_data.pTxDMAy_Streamx = DMA2_Stream7; // pointer to the DMA stream
usart1_io.Rx.pDeviceData = (void*) &usart1_device_data;
usart1_io.Tx.pDeviceData = (void*) &usart1_device_data;
usart1_io.Rx.pBuf = usart1_rx_buffer;
usart1_io.Tx.pBuf = usart1_tx_buffer;
strncpy( usart1_io.Rx.name, "usart1 Rx", sizeof( usart1_io.Rx.name ) );
strncpy( usart1_io.Tx.name, "usart1 Tx", sizeof( usart1_io.Tx.name ) );
// Initialise the stream fifos.
stream_init(
&usart1_io,
(void*)usart_Rx_callback,
(void*)usart_Tx_callback,
sizeof( usart1_rx_buffer ),
sizeof( usart1_tx_buffer )
);
Init_USART(
&usart1_io, // stream_io_t *stream_io,
&usart1_device_data,
// DMA_Channel_4, // Rx DMA not used
DMA_Channel_4
);
#endif /* USE_USART1 */
------------------------------------------------------------
void
Init_USART(
stream_io_t *stream_io,
usart_dev_t *pDeviceData,
// uint32_t Rx_DMA_Channel,
uint32_t Tx_DMA_Channel
)
{
/* set up Baud rate, character format and stop/start */
pDeviceData->USART_InitStructure.USART_BaudRate = DEFAULT_BAUD;
pDeviceData->USART_InitStructure.USART_WordLength = USART_WordLength_8b;
pDeviceData->USART_InitStructure.USART_StopBits = USART_StopBits_2;
pDeviceData->USART_InitStructure.USART_Parity = USART_Parity_No;
pDeviceData->USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
pDeviceData->USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // default
// special cases
//switch( (uint32_t)(pDeviceData->pUSART) )
//{
//case (uint32_t)USART2: pDeviceData->USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_CTS; break;
//}
USART_Init( pDeviceData->pUSART, &(pDeviceData->USART_InitStructure) );
DMA_DeInit( pDeviceData->pTxDMAy_Streamx );
pDeviceData->DMA_InitStructure.DMA_Channel = Tx_DMA_Channel;
pDeviceData->DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
pDeviceData->DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)stream_io->Tx.pBuf;
pDeviceData->DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
pDeviceData->DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(pDeviceData->pUSART->DR);
pDeviceData->DMA_InitStructure.DMA_BufferSize = (uint16_t)0; // Nothing to send yet.
// and zero causes a hard-fault
// DMA_Init( pDeviceData->pTxDMAy_Streamx, &(pDeviceData->DMA_InitStructure) ); // so do this in the callback
// Read SR the TC bit
USART_GetFlagStatus( pDeviceData->pUSART, USART_FLAG_TC);
// (ignore returned data)
/* Enable USART */
USART_DMACmd( pDeviceData->pUSART, USART_DMAReq_Tx, ENABLE); // TODO .. Can we do this before DMA_Init()? (appears OK)
USART_Cmd( pDeviceData->pUSART, ENABLE);
USART_ITConfig( pDeviceData->pUSART, USART_IT_RXNE, ENABLE); // enable Rx interrupts
stream_io->Rx.active = 1;
stream_io->Tx.active = 1;
}
------------------------------------------------------------
int16_t
usart_Tx_callback( stream_io_t *stream_io )
{
int16_t n = 0;
static int t;
usart_dev_t *pDevData;
pDevData = stream_io->Tx.pDeviceData;
if( DISABLE == DMA_GetCmdStatus( pDevData->pTxDMAy_Streamx ) ) // If the DMA is ready
{
if( stream_io->Tx.pTail != stream_io->Tx.pMark ) // update data from previous send
{
// (clip wrap calculations)
}
if( stream_io->Tx.size > stream_io->Tx.free ) // If there's something to send.
{
uint32_t flags = 0;
// Well this is fairly silly .. we must use a pointer to the DMA+Stream,
// but the flag bits are not appropriately abstracted :-(
switch( (uint32_t)(pDevData->pUSART) )
{
case (uint32_t)USART1: flags = DMA_IT_FEIF1|DMA_IT_HTIF1|DMA_IT_TCIF1|DMA_IT_TEIF1; break;
case (uint32_t)USART2: flags = DMA_IT_FEIF2|DMA_IT_HTIF2|DMA_IT_TCIF2|DMA_IT_TEIF2; break;
case (uint32_t)USART3: flags = DMA_IT_FEIF3|DMA_IT_HTIF3|DMA_IT_TCIF3|DMA_IT_TEIF3; break;
case (uint32_t)USART4: flags = DMA_IT_FEIF4|DMA_IT_HTIF4|DMA_IT_TCIF4|DMA_IT_TEIF4; break;
case (uint32_t)USART5: flags = DMA_IT_FEIF5|DMA_IT_HTIF5|DMA_IT_TCIF5|DMA_IT_TEIF5; break;
case (uint32_t)USART6: flags = DMA_IT_FEIF6|DMA_IT_HTIF6|DMA_IT_TCIF6|DMA_IT_TEIF6; break;
}
DMA_ClearITPendingBit( pDevData->pTxDMAy_Streamx, flags );
n = stream_io->Tx.pHead - stream_io->Tx.pTail; // Find out how much to send.
if( n != 0 ) // zero means we've sent it all.
{
if( n < 0 ) // It'll wrap ...
{
//(clip wrap calculations)
}
pDevData->DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)stream_io->Tx.pTail;
pDevData->DMA_InitStructure.DMA_BufferSize = (uint16_t)n;
DMA_Init( pDevData->pTxDMAy_Streamx, &(pDevData->DMA_InitStructure) );
DMA_Cmd( pDevData->pTxDMAy_Streamx, ENABLE);
}
}
}
return n;
}
USARTs.c
-
Looks like I have flags wrong. Those FEIFx flags are for DMA streams not USARTs.
I think the StdPeripherals example I started from was on USART3, which happens to be on Stream3. Doh!
The flags clearing clip should have looked like the following, not as I had it.
switch( (uint32_t)(pDevData->pUSART) )
{
case (uint32_t)USART1: flags = DMA_IT_FEIF7|DMA_IT_HTIF7|DMA_IT_TCIF7|DMA_IT_TEIF7; break;
case (uint32_t)USART2: flags = DMA_IT_FEIF6|DMA_IT_HTIF6|DMA_IT_TCIF6|DMA_IT_TEIF6; break;
case (uint32_t)USART3: flags = DMA_IT_FEIF3|DMA_IT_HTIF3|DMA_IT_TCIF3|DMA_IT_TEIF3; break;
case (uint32_t)USART4: flags = DMA_IT_FEIF4|DMA_IT_HTIF4|DMA_IT_TCIF4|DMA_IT_TEIF4; break;
case (uint32_t)USART5: flags = DMA_IT_FEIF7|DMA_IT_HTIF7|DMA_IT_TCIF7|DMA_IT_TEIF7; break;
case (uint32_t)USART6: flags = DMA_IT_FEIF6|DMA_IT_HTIF6|DMA_IT_TCIF6|DMA_IT_TEIF6; break;
}
Please sign in to leave a comment.
Comments
2 comments