2018-10-28 01:06 AM
I generated a project using the LL libraries for the STM32L011 as the HAL is far too bloated to use with this part. After porting some known working DMA TX code from an old F103 StdPeriph project, I couldn't get anything to transmit out. What I found was missing was that the initialization function never sets the peripheral address to be the UART's TDR. Calling the following line solves the problem and I believe it should be done in the intialization instead of during the TX function where I have it now from debugging:
LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)&LPUART1->TDR);
My DMA TX function for reference:
void LPUART_DMA_TX(uint8_t* data, uint8_t size)
{
LL_LPUART_DisableDMAReq_TX(LPUART1); // Disable DMA requests from LPUART
LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2); // Disable DMA channel
LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)&LPUART1->TDR);
while (DMA1_Channel2->CCR & 0x01) // While EN bit is high
__NOP(); // Wait for disable to finish
LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, size);
LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_2, (uint32_t)data); // Set source address
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_LOW);
LL_DMA_ClearFlag_GI2(DMA1); // Clear global interrupt flag for channel 2
LL_DMA_ClearFlag_TC2(DMA1);
LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_2); // Enable transfer complete interrupt
LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_2);
LL_LPUART_EnableDMAReq_TX(LPUART1); // Enable DMA requests
LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2); // Enable channel
LL_LPUART_ClearFlag_TC(LPUART1);
}
The generated code from CubeMX is as follows (uses DMA channels 2 and 3 for TX/RX respectively):
/* LPUART1 init function */
static void MX_LPUART1_UART_Init(void)
{
LL_LPUART_InitTypeDef LPUART_InitStruct;
LL_GPIO_InitTypeDef GPIO_InitStruct;
/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_LPUART1);
/**LPUART1 GPIO Configuration
PA1 ------> LPUART1_TX
PA3 ------> LPUART1_RX
*/
GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Alternate = LL_GPIO_AF_6;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
GPIO_InitStruct.Alternate = LL_GPIO_AF_6;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* LPUART1 DMA Init */
/* LPUART1_TX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_2, LL_DMA_REQUEST_5);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_2, LL_DMA_MDATAALIGN_BYTE);
/* LPUART1_RX Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_3, LL_DMA_REQUEST_5);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PRIORITY_LOW);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MODE_NORMAL);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_BYTE);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_BYTE);
/* LPUART1 interrupt Init */
NVIC_SetPriority(AES_RNG_LPUART1_IRQn, 0);
NVIC_EnableIRQ(AES_RNG_LPUART1_IRQn);
LPUART_InitStruct.BaudRate = 57600;
LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
}