2019-08-02 07:58 AM
I'm using the stm32f103 and I'm trying to send a text stored in SRAM via DMA to the USART 2 peripheral. My assumption is I'll turn on the usart2 TX dma ( DMAT )request whenever I need it and turn it off after the current transmission completes, (i.e In the DMA1_Channel7_IRQHandler). That is to say when I call the serialPrint function(DEFINED IN MY CODE) USART2 DMAT is turned ON and the DMA1 will serve it. But nothing seems working. The DMA1_Channel7_IRQHandler is not serviced after all.
I spent a lot of time in this problem but I couldn't get it working. Somebody help, thanks. Below is my code....
/*
I'll use DMA to move data from memory to the usart2 peripheral.
*/
#include "stm32f10x.h" // Device header
#include <string.h>
void clockConfig(void);
void usart2Init(void);
void DMA1channel7Init(void);
void serialPrint(char* data, uint16_t bufLen);
uint8_t sendBuf[64];
int main(void)
{
clockConfig();
usart2Init();
DMA1channel7Init();
serialPrint("Hello Serial1\n\r", 15);
while(1)
{
}
}
void serialPrint(char* data, uint16_t bufLen)
{
memcpy(sendBuf, data, bufLen);
// DMA1_Channel 7 number of transfer bytes
DMA1_Channel7->CNDTR = bufLen;
// Enable USART2_Tx DMA Request
USART2->CR3 |= USART_CR3_DMAT;
}
void DMA1_Channel7_IRQHandler(void)
{
if( DMA1->ISR & DMA_ISR_TCIF7 )
{
// Disable transfer complete flag
DMA1->IFCR |= DMA_IFCR_CTCIF7;
// Disable DMA request
USART2->CR3 &= ~USART_CR3_DMAT;
}
}
void usart2Init(void)
{
// USART2_Tx: PA2
// Enable clock access for port A
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// Configure PA2 as AF push pull
GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_MODE2;
GPIOA->CRL &= ~GPIO_CRL_CNF2_0;
// Enable clock access for USART2
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
// @36MHz 9600bps
USART2->BRR = 0xEA6;
// Enable USART2_Tx
USART2->CR1 |= USART_CR1_TE;
// Enable USART2
USART2->CR1 |= USART_CR1_UE;
}
void DMA1channel7Init(void)
{
// Enable clock access for DMA1
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
// Configure DMA1_Channel7
// peripheral address
DMA1_Channel7->CPAR = (uint32_t)&USART2->DR;
// Memory address
DMA1_Channel7->CMAR = (uint32_t)sendBuf;
// Direction is from memory to peripheral
DMA1_Channel7->CCR |= DMA_CCR7_DIR;
// Memory increment
DMA1_Channel7->CCR |= DMA_CCR7_MINC;
// 1Byte memory and peripheral size
DMA1_Channel7->CCR &= ~( DMA_CCR7_MSIZE | DMA_CCR7_PSIZE );
// Enable transmission complete interrupt
DMA1_Channel7->CCR |= DMA_CCR7_TCIE;
NVIC_EnableIRQ(DMA1_Channel7_IRQn);
// Enable DMA
DMA1_Channel7->CCR |= DMA_CCR7_EN;
}
void clockConfig(void)
{
// HSE ON
RCC->CR |= 0x1<<16;
// wait unit HSE is ready
while(!(RCC->CR & (0x1<<17))){}
// PLL OFF
RCC->CR &= ~(0x1<<24);
//HSE clock not divided
RCC->CFGR &= ~(0x1<<17);
// PLL SRC = HSE
RCC->CFGR |= 0x1<<16;
// PLL MUL, x9
RCC->CFGR &= ~(0xF<<18);
RCC->CFGR |= 0x7<<18;
// PLL ON
RCC->CR |= 0x1<<24;
// wait until PLL is ready
while(!(RCC->CR & (0x1 << 25))){}
// choose PLL as Sys clock
RCC->CFGR &= ~(0x3);
RCC->CFGR |= 0x2;
// AHB prescaler x1
RCC->CFGR &= ~(0xF<<4);
// APB1 (36MHz max ) prescaler /2
RCC->CFGR &= ~(0x7<<8);
RCC->CFGR |= (0x4<<8);
// APB2(72MHz) prescaler x1
RCC->CFGR &= ~(0x7<<11);
}
Solved! Go to Solution.
2019-08-14 08:43 AM
I got it working. The reason is DMA CNDTR can only be written when the
channel is disabled. If you try writing when enabled it basically treats it as a zero, So no transfer occurs.
2019-08-02 10:57 AM
Polled Tx (i.e. without DMA) works?
JW
2019-08-02 06:59 PM
Yes, not exactly the same code though.
2019-08-03 12:16 AM
I don't see any problem in your code. I don't use 'F1 though.
Make sure the respective TCIFx DMA status flag is clear before you enable the DMA channel.
Read out and check the content of respective DMA, GPIO and USART registers.
JW
2019-08-03 04:03 AM
Thanks buddy. I appreciate your help. I think everything is setup correctly. But I don't know what the problem is:sad_but_relieved_face:
2019-08-08 10:47 AM
I had the same problem. It is not documented, but problem is because DMA TC interrupt flag triggers when the las 16 bits data have been transfered.
For example here I am passing 16 bytes from memory sram to uart, when TC is triggered I have toggle a pin, and it is clear that transfer is not totally complete in uart, but for dma is complete. Just the las two bytes are not complete transfered in UART peripheral.
2019-08-14 08:43 AM
I got it working. The reason is DMA CNDTR can only be written when the
channel is disabled. If you try writing when enabled it basically treats it as a zero, So no transfer occurs.