2020-07-06 11:47 AM
Hi,
Can someone help me identify what I am doing wrong ?
Still having issues with the DMA, but with Rx DMA instead. The issue with Tx DMA is fixed.
I am trying to send 4 chars from a terminal to the H743 rxbuf array using DMA.
In the debugger window, the sent chars can be seen in USART2->RDR
But DMA Rx does not happen (Transfer Complete/Transfer ERROR)
Any thoughts ?
Thanks,
Manu
/**
* UART3 DMA Rx test application over ST Link Virtual COM Port
* LED1 Blinks after DMA Transfer Complete
* LED2 Blinks in case of DMA Transfer Error
*/
#include "stm32h7xx_ll_bus.h"
#include "stm32h7xx_ll_cortex.h"
#include "stm32h7xx_ll_dma.h"
#include "stm32h7xx_ll_gpio.h"
#include "stm32h7xx_ll_pwr.h"
#include "stm32h7xx_ll_rcc.h"
#include "stm32h7xx_ll_system.h"
#include "stm32h7xx_ll_usart.h"
#include "stm32h7xx_ll_utils.h"
#define APB_Div 4
__IO uint8_t tx_done = 0;
__IO uint8_t rx_done = 0;
const uint8_t txstr[] = "STM32H743 USART DMA TxRx Test: \r\n Type something! Look at LED status\r\n";
uint8_t txlen = sizeof (txstr);
#define RXBUFLEN 16
uint8_t rxbuf[RXBUFLEN] = { 0 };
uint8_t rxlen = 4;
/**
* System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL1 (HSE BYPASS)
* SYSCLK(Hz) = 400000000 (CPU Clock)
* HCLK(Hz) = 200000000 (AXI and AHBs Clock)
* AHB Prescaler = 2
* D1 APB3 Prescaler = 2 (APB3 Clock 100MHz)
* D2 APB1 Prescaler = 2 (APB1 Clock 100MHz)
* D2 APB2 Prescaler = 2 (APB2 Clock 100MHz)
* D3 APB4 Prescaler = 2 (APB4 Clock 100MHz)
* HSE Frequency(Hz) = 8000000
* PLL_M = 4
* PLL_N = 400
* PLL_P = 2
* PLL_Q = 4
* PLL_R = 2
* VDD(V) = 3.3
* Flash Latency(WS) = 4
*/
static void SystemClock_Config(void)
{
/* Power Configuration */
LL_PWR_ConfigSupply(LL_PWR_LDO_SUPPLY);
LL_PWR_SetRegulVoltageScaling(LL_PWR_REGU_VOLTAGE_SCALE1);
while (LL_PWR_IsActiveFlag_VOS() == 0) { }
LL_RCC_HSE_EnableBypass();
LL_RCC_HSE_Enable();
while (LL_RCC_HSE_IsReady() != 1) { }
LL_FLASH_SetLatency(LL_FLASH_LATENCY_4);
/* Main PLL configuration and activation */
LL_RCC_PLL_SetSource(LL_RCC_PLLSOURCE_HSE);
LL_RCC_PLL1P_Enable();
LL_RCC_PLL1Q_Enable();
LL_RCC_PLL1R_Enable();
LL_RCC_PLL1FRACN_Disable();
LL_RCC_PLL1_SetVCOInputRange(LL_RCC_PLLINPUTRANGE_2_4);
LL_RCC_PLL1_SetVCOOutputRange(LL_RCC_PLLVCORANGE_WIDE);
LL_RCC_PLL1_SetM(4);
LL_RCC_PLL1_SetN(400);
LL_RCC_PLL1_SetP(2);
LL_RCC_PLL1_SetQ(4);
LL_RCC_PLL1_SetR(2);
LL_RCC_PLL1_Enable();
while (LL_RCC_PLL1_IsReady() != 1) { }
LL_RCC_SetSysPrescaler(LL_RCC_SYSCLK_DIV_1);
LL_RCC_SetAHBPrescaler(LL_RCC_AHB_DIV_2);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_2);
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_2);
LL_RCC_SetAPB4Prescaler(LL_RCC_APB4_DIV_2);
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL1); /* PLL1 as System Clock Source */
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) { }
SysTick_Config(400000000 / 1000); /* 1ms Systick */
SystemCoreClock = 400000000;
}
void led_init(void)
{
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOB); /* GPIO Clk */
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOE);
LL_GPIO_SetPinMode(GPIOB,
LL_GPIO_PIN_0,
LL_GPIO_MODE_OUTPUT); /* PB.0 -> LED1 */
LL_GPIO_SetPinMode(GPIOE,
LL_GPIO_PIN_1,
LL_GPIO_MODE_OUTPUT); /* PE.1 -> LED2 */
LL_GPIO_SetPinMode(GPIOB,
LL_GPIO_PIN_14,
LL_GPIO_MODE_OUTPUT); /* PB.14 -> LED3 */
}
void config_usart(void)
{
LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOD); /* GPIO Clk */
LL_GPIO_SetPinMode(GPIOD, LL_GPIO_PIN_8, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_8_15(GPIOD, LL_GPIO_PIN_8, LL_GPIO_AF_7);
LL_GPIO_SetPinSpeed(GPIOD, LL_GPIO_PIN_8, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(GPIOD, LL_GPIO_PIN_8, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(GPIOD, LL_GPIO_PIN_8, LL_GPIO_PULL_UP);
LL_GPIO_SetPinMode(GPIOD, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_8_15(GPIOD, LL_GPIO_PIN_9, LL_GPIO_AF_7);
LL_GPIO_SetPinSpeed(GPIOD, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinOutputType(GPIOD, LL_GPIO_PIN_9, LL_GPIO_OUTPUT_PUSHPULL);
LL_GPIO_SetPinPull(GPIOD, LL_GPIO_PIN_9, LL_GPIO_PULL_UP);
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART3); /* USART3 Clk */
LL_RCC_SetUSARTClockSource(LL_RCC_USART234578_CLKSOURCE_PCLK1); /* Clk source */
LL_USART_SetTransferDirection(USART3, LL_USART_DIRECTION_TX_RX);
LL_USART_ConfigCharacter(USART3,
LL_USART_DATAWIDTH_8B,
LL_USART_PARITY_NONE,
LL_USART_STOPBITS_1);
LL_USART_SetBaudRate(USART3,
(SystemCoreClock / APB_Div),
LL_USART_PRESCALER_DIV1,
LL_USART_OVERSAMPLING_16,
115200);
LL_USART_Enable(USART3);
while ((!(LL_USART_IsActiveFlag_TEACK(USART3))) ||
(!(LL_USART_IsActiveFlag_REACK(USART3)))) { }
}
/**
* Bugfix!
* 2.3.1 DMA stream locked when transferring UART data
*
* Description:
* When a USART/UART is issuing a DMA request to transfer data,
* if a concurrent transfer occurs, the requested transfer
* may not be served and the DMA stream may stay locked.
*
* Workaround:
* Use the alternative peripheral DMA channel protocol
* by setting bit 20 of the DMA_SxCR register.
*/
__STATIC_INLINE void LL_DMA_EnablePeriphDMA(DMA_TypeDef *DMAx, uint32_t Stream)
{
register uint32_t dma_base_addr = (uint32_t)DMAx;
SET_BIT(((DMA_Stream_TypeDef *)(dma_base_addr + LL_DMA_STR_OFFSET_TAB[Stream]))->CR, DMA_SxCR_TRBUFF);
}
//__STATIC_INLINE void LL_DMA_DisablePeriphDMA(DMA_TypeDef *DMAx, uint32_t Stream)
//{
// register uint32_t dma_base_addr = (uint32_t)DMAx;
// CLEAR_BIT(((DMA_Stream_TypeDef *)(dma_base_addr + LL_DMA_STR_OFFSET_TAB[Stream]))->CR, DMA_SxCR_TRBUFF);
//}
void config_dma(void)
{
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); /* enable DMA1 clock */
/* Rx DMA */
LL_DMA_SetPeriphRequest(DMA1,
LL_DMA_STREAM_1, /* Request DMA stream 1 */
LL_DMAMUX1_REQ_USART3_RX); /* for DMAMUX1 USART3 Rx */
LL_DMA_SetDataTransferDirection(DMA1,
LL_DMA_STREAM_1,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetStreamPriorityLevel(DMA1, LL_DMA_STREAM_1, LL_DMA_PRIORITY_HIGH);
LL_DMA_SetMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_STREAM_1, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_1, LL_DMA_PDATAALIGN_BYTE);
/* DMA IRQ */
LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_1); /* Rx Transfer Complete */
LL_DMA_EnableIT_TE(DMA1, LL_DMA_STREAM_1); /* Rx Transfer Error */
NVIC_SetPriority(DMA1_Stream1_IRQn, 0); /* Rx Stream Priority */
NVIC_EnableIRQ(DMA1_Stream1_IRQn); /* Rx Global IRQ */
LL_USART_EnableDMAReq_RX(USART3); /* Enable Rx DMARQ */
LL_DMA_ConfigAddresses(DMA1,
LL_DMA_STREAM_1,
LL_USART_DMA_GetRegAddr(USART3, LL_USART_DMA_REG_DATA_RECEIVE),
(uint32_t)rxbuf,
LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_STREAM_1));
LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_1, rxlen);
LL_DMA_EnablePeriphDMA(DMA1, LL_DMA_STREAM_1); /* Enable USART Rx DMA */
LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_1); /* Enable DMA Channel Rx */
}
void led_blink(uint8_t led, uint32_t Period)
{
while (1) {
switch (led) {
case 1:
LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_0);
break;
case 2:
LL_GPIO_TogglePin(GPIOE, LL_GPIO_PIN_1);
break;
case 3:
LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_14);
break;
}
LL_mDelay(Period);
}
}
void DMA1_Stream1_IRQHandler(void)
{
if (LL_DMA_IsActiveFlag_TC1(DMA1)) {
LL_DMA_ClearFlag_TC1(DMA1);
rx_done = 1;
// LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_0); /* Done: LED ON */
led_blink(1, 100);
} else if (LL_DMA_IsActiveFlag_TE1(DMA1)) {
// LL_DMA_DisablePeriphDMA(DMA1, LL_DMA_STREAM_1); /* Disable USART Rx DMA */
led_blink(2, 1000); /* loop in here */
}
}
int main(void)
{
SystemClock_Config();
led_init();
config_dma();
config_usart();
while (1) {
}
}
2020-07-06 02:48 PM
Please see these examples. They work.
-- pa
2020-07-06 04:03 PM
It seems to be missing files "lwrb/lwrb.h"
So, I tried the usart_init() and SystemClock_Config() functions;
But that gives me a DMA TEIF0, trying to read data from a terminal.
The code's working at your end ?
2020-07-08 08:25 AM
Identified the issue as the buffer is placed in DTCM ?
Moving it to AXI SRAM did fix the issue.
2021-12-04 12:44 AM
i just use hal not LL, and uart with dma makes sense.